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())