Files
pyside6_contactos_sqlite/main.py
T
2026-08-04 16:58:48 +02:00

137 lines
4.9 KiB
Python
Executable File

import sys
import os
from PySide6.QtWidgets import (
QApplication, QWidget, QVBoxLayout, QLineEdit,
QTableView, QHBoxLayout, QPushButton, QLabel, QHeaderView
)
from PySide6.QtCore import Qt
from PySide6.QtSql import QSqlDatabase, QSqlTableModel
from PySide6.QtCore import QSortFilterProxyModel
class ContactosApp(QWidget):
def __init__(self):
super().__init__()
self.setWindowTitle("Contactos")
self.setMinimumSize(600, 400)
# self.setWindowIcon(os.path.join("icons", "app.ico"))
# Layout principal
main_layout = QVBoxLayout()
self.setLayout(main_layout)
# Header con título y switch claro/oscuro
header_layout = QHBoxLayout()
title = QLabel("📇 Contactos")
title.setStyleSheet("font-weight: bold; font-size: 16px;")
header_layout.addWidget(title)
self.theme_btn = QPushButton("🌗 Modo oscuro")
self.theme_btn.setCheckable(True)
self.theme_btn.clicked.connect(self.toggle_theme)
header_layout.addStretch()
header_layout.addWidget(self.theme_btn)
main_layout.addLayout(header_layout)
# Buscador
self.search_input = QLineEdit()
self.search_input.setPlaceholderText("🔍 Buscar por nombre…")
self.search_input.textChanged.connect(self.buscar)
main_layout.addWidget(self.search_input)
# Tabla de contactos
self.table = QTableView()
main_layout.addWidget(self.table)
# Conexión a DB SQLite
db_path = os.path.join("database", "contactos.db")
self.db = QSqlDatabase.addDatabase("QSQLITE")
self.db.setDatabaseName(db_path)
if not self.db.open():
raise Exception("No se pudo abrir la base de datos")
# Modelo y proxy para búsqueda
self.model = QSqlTableModel(db=self.db)
self.model.setTable("contactos")
self.model.select()
# Encabezados más amigables
self.model.setHeaderData(1, Qt.Horizontal, "Nombre")
self.model.setHeaderData(2, Qt.Horizontal, "Teléfono")
self.model.setHeaderData(3, Qt.Horizontal, "Tel. corto")
self.model.setHeaderData(4, Qt.Horizontal, "Email")
self.proxy = QSortFilterProxyModel()
self.proxy.setSourceModel(self.model)
self.proxy.setFilterKeyColumn(1) # Solo nombre
self.proxy.setFilterCaseSensitivity(Qt.CaseInsensitive)
self.table.setModel(self.proxy)
self.table.hideColumn(0)
self.table.setEditTriggers(QTableView.NoEditTriggers)
self.table.setSelectionBehavior(QTableView.SelectRows)
self.table.setSelectionMode(QTableView.SingleSelection)
self.table.setAlternatingRowColors(True)
header = self.table.horizontalHeader()
header.setSectionResizeMode(QHeaderView.Interactive)
header.setSectionResizeMode(1, QHeaderView.Stretch) # Nombre
header.setSectionResizeMode(4, QHeaderView.Stretch) # Email
# self.table.resizeColumnsToContents()
# self.table.setColumnWidth(1, 200) # Nombre
# self.table.setColumnWidth(2, 120) # Teléfono
# self.table.setColumnWidth(3, 80) # Tel. corto
# self.table.setColumnWidth(4, 250) # Email
self.table.keyPressEvent = lambda event: (
self.copiar_fila()
if event.matches(QKeySequence.Copy)
else QTableView.keyPressEvent(self.table, event)
)
# Aplicar tema claro por defecto
self.aplicar_tema("light")
def buscar(self, texto):
# self.proxy.setFilterFixedString(texto) #coincidencias exactas
self.proxy.setFilterRegularExpression(texto) #buscar tipo %like%
def toggle_theme(self):
if self.theme_btn.isChecked():
self.aplicar_tema("dark")
self.theme_btn.setText("🌞 Modo claro")
else:
self.aplicar_tema("light")
self.theme_btn.setText("🌗 Modo oscuro")
def aplicar_tema(self, modo):
qss_path = os.path.join("styles", f"{modo}.qss")
if os.path.exists(qss_path):
with open(qss_path, "r") as f:
self.setStyleSheet(f.read())
def copiar_fila(self):
selection = self.table.selectionModel().selectedRows()
if not selection:
return
row = selection[0].row()
columnas = self.proxy.columnCount()
datos = []
for col in range(columnas):
if self.table.isColumnHidden(col):
continue
index = self.proxy.index(row, col)
datos.append(str(self.proxy.data(index)))
texto = " | ".join(datos)
QApplication.clipboard().setText(texto)
if __name__ == "__main__":
app = QApplication(sys.argv)
ventana = ContactosApp()
ventana.show()
sys.exit(app.exec())