137 lines
4.9 KiB
Python
Executable File
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())
|