Libreta de direcciones
El ejemplo de la libreta de direcciones muestra cómo utilizar modelos proxy para mostrar diferentes vistas de los datos de un único modelo.

Este ejemplo proporciona una libreta de direcciones que permite agrupar los contactos alfabéticamente en 9 grupos: ABC, DEF, GHI, ... VW, ..., XYZ. Esto se consigue utilizando múltiples vistas sobre el mismo modelo, cada una de las cuales se filtra utilizando una instancia de la clase QSortFilterProxyModel.
Visión general
La libreta de direcciones contiene 5 clases: MainWindow, AddressWidget, TableModel, NewAddressTab y AddDialog. La clase MainWindow utiliza AddressWidget como widget central y proporciona los menús File y Tools.

La clase AddressWidget es una subclase de QTabWidget que se utiliza para manipular las 10 pestañas que se muestran en el ejemplo: las 9 pestañas de grupos alfabéticos y una instancia de NewAddressTab. La clase NewAddressTab es una subclase de QWidget que sólo se utiliza cuando la libreta de direcciones está vacía, lo que incita al usuario a añadir algunos contactos. AddressWidget también interactúa con una instancia de TableModel para añadir, editar y eliminar entradas de la libreta de direcciones.
TableModel es una subclase de QAbstractTableModel que proporciona la API modelo/vista estándar para acceder a los datos. Contiene una lista de contactos añadidos. Sin embargo, estos datos no están todos visibles en una única pestaña. En su lugar, QTableView se utiliza para proporcionar 9 vistas diferentes de los mismos datos, según los grupos alfabéticos.
QSortFilterProxyModel es la clase responsable de filtrar los contactos para cada grupo de contactos. Cada modelo proxy utiliza un QRegularExpression para filtrar los contactos que no pertenecen al grupo alfabético correspondiente. La clase AddDialog se utiliza para obtener información del usuario para la libreta de direcciones. Esta subclase QDialog es instanciada por NewAddressTab para añadir contactos, y por AddressWidget para añadir y editar contactos.
Comenzaremos viendo la implementación de TableModel.
Definición de la clase TableModel
La clase TableModel proporciona una API estándar para acceder a los datos de su lista de contactos mediante la subclase QAbstractTableModel. Las funciones básicas que deben implementarse para ello son: rowCount(), columnCount(), data(), headerData(). Para que TableModel sea editable, debe proporcionar implementaciones de las funciones insertRows(), removeRows(), setData() y flags().
struct Contact { QString name; QString address; bool operator==(const Contact &other) const { return name == other.name && address == other.address; } }; inline QDataStream &operator<<(QDataStream &stream, const Contact &contact) { return stream << contact.name << contact.address; } inline QDataStream &operator>>(QDataStream &stream, Contact &contact) { return stream >> contact.name >> contact.address; } class TableModel : public QAbstractTableModel { Q_OBJECT public: TableModel(QObject *parent = nullptr); TableModel(const QList<Contact> &contacts, QObject *parent = nullptr); int rowCount(const QModelIndex &parent) const override; int columnCount(const QModelIndex &parent) const override; QVariant data(const QModelIndex &index, int role) const override; QVariant headerData(int section, Qt::Orientation orientation, int role) const override; Qt::ItemFlags flags(const QModelIndex &index) const override; bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole) override; bool insertRows(int position, int rows, const QModelIndex &index = QModelIndex()) override; bool removeRows(int position, int rows, const QModelIndex &index = QModelIndex()) override; const QList<Contact> &getContacts() const; private: QList<Contact> contacts; };
Se utilizan dos constructores, uno por defecto que utiliza TableModel's own QList<Contact> y otro que toma QList<Contact> como argumento, por conveniencia.
Implementación de la clase TableModel
Implementamos los dos constructores tal y como se definen en el fichero de cabecera. El segundo constructor inicializa la lista de contactos del modelo, con el valor del parámetro.
TableModel::TableModel(QObject *parent) : QAbstractTableModel(parent) { } TableModel::TableModel(const QList<Contact> &contacts, QObject *parent) : QAbstractTableModel(parent), contacts(contacts) { }
Las funciones rowCount() y columnCount() devuelven las dimensiones del modelo. Mientras que el valor de rowCount() variará en función del número de contactos añadidos a la agenda, el valor de columnCount() es siempre 2 porque sólo necesitamos espacio para las columnas Nombre y Dirección.
int TableModel::rowCount(const QModelIndex &parent) const { return parent.isValid() ? 0 : contacts.size(); } int TableModel::columnCount(const QModelIndex &parent) const { return parent.isValid() ? 0 : 2; }
La función data() devuelve un Nombre o una Dirección, en función del contenido del índice del modelo suministrado. El número de fila almacenado en el índice del modelo se utiliza para hacer referencia a un elemento de la lista de contactos. La selección se gestiona mediante la función QItemSelectionModel, que se explicará con AddressWidget.
QVariant TableModel::data(const QModelIndex &index, int role) const { if (!index.isValid()) return QVariant(); if (index.row() >= contacts.size() || index.row() < 0) return QVariant(); if (role == Qt::DisplayRole) { const auto &contact = contacts.at(index.row()); switch (index.column()) { case 0: return contact.name; case 1: return contact.address; default: break; } } return QVariant(); }
La función headerData() muestra la cabecera de la tabla, Nombre y Dirección. Si necesita entradas numeradas para su libreta de direcciones, puede utilizar una cabecera vertical que hemos ocultado en este ejemplo (véase la implementación de AddressWidget ).
QVariant TableModel::headerData(int section, Qt::Orientation orientation, int role) const { if (role != Qt::DisplayRole) return QVariant(); if (orientation == Qt::Horizontal) { switch (section) { case 0: return tr("Name"); case 1: return tr("Address"); default: break; } } return QVariant(); }
La función insertRows() se llama antes de añadir nuevos datos, de lo contrario éstos no se mostrarán. Las funciones beginInsertRows() y endInsertRows() se ejecutan para garantizar que todas las vistas conectadas conozcan los cambios.
bool TableModel::insertRows(int position, int rows, const QModelIndex &index) { Q_UNUSED(index); beginInsertRows(QModelIndex(), position, position + rows - 1); for (int row = 0; row < rows; ++row) contacts.insert(position, { QString(), QString() }); endInsertRows(); return true; }
La función removeRows() se ejecuta para eliminar datos. De nuevo, se llama a beginRemoveRows() y endRemoveRows() para asegurarse de que todas las vistas conectadas conocen los cambios.
bool TableModel::removeRows(int position, int rows, const QModelIndex &index) { Q_UNUSED(index); beginRemoveRows(QModelIndex(), position, position + rows - 1); for (int row = 0; row < rows; ++row) contacts.removeAt(position); endRemoveRows(); return true; }
La función setData() es la función que inserta datos en la tabla, elemento por elemento y no fila por fila. Esto significa que para rellenar una fila de la libreta de direcciones, hay que llamar dos veces a setData(), ya que cada fila tiene 2 columnas. Es importante emitir la señal dataChanged(), ya que indica a todas las vistas conectadas que actualicen sus visualizaciones.
bool TableModel::setData(const QModelIndex &index, const QVariant &value, int role) { if (index.isValid() && role == Qt::EditRole) { const int row = index.row(); auto contact = contacts.value(row); switch (index.column()) { case 0: contact.name = value.toString(); break; case 1: contact.address = value.toString(); break; default: return false; } contacts.replace(row, contact); emit dataChanged(index, index, {Qt::DisplayRole, Qt::EditRole}); return true; } return false; }
La función flags() devuelve las banderas de elementos para el índice dado.
Qt::ItemFlags TableModel::flags(const QModelIndex &index) const { if (!index.isValid()) return Qt::ItemIsEnabled; return QAbstractTableModel::flags(index) | Qt::ItemIsEditable; }
Fijamos la bandera Qt::ItemIsEditable porque queremos permitir que se edite TableModel. Aunque para este ejemplo no utilizamos las características de edición del objeto QTableView, las habilitamos aquí para poder reutilizar el modelo en otros programas.
La última función en TableModel, getContacts() devuelve el objeto QList<Contact> que contiene todos los contactos de la libreta de direcciones. Utilizamos esta función más adelante para obtener la lista de contactos para comprobar si existen entradas, escribir los contactos en un archivo y leerlos de nuevo. Encontrará más explicaciones en AddressWidget.
const QList<Contact> &TableModel::getContacts() const { return contacts; }
Definición de la clase AddressWidget
La clase AddressWidget es técnicamente la clase principal involucrada en este ejemplo ya que proporciona funciones para añadir, editar y eliminar contactos, para guardar los contactos en un fichero y para cargarlos desde un fichero.
class AddressWidget : public QTabWidget { Q_OBJECT public: AddressWidget(QWidget *parent = nullptr); void readFromFile(); void writeToFile(); public slots: void showAddEntryDialog(); void addEntry(const QString &name, const QString &address); void editEntry(); void removeEntry(); signals: void selectionChanged (const QItemSelection &selected); private: void setupTabs(); inline static QString fileName = QStandardPaths::standardLocations(QStandardPaths::TempLocation).value(0) + QStringLiteral("/addressbook.dat"); TableModel *table; NewAddressTab *newAddressTab; };
AddressWidget Extiende QTabWidget para poder contener 10 pestañas (NewAddressTab y las 9 pestañas de grupos alfabéticos) y también manipula table, el objeto TableModel, proxyModel, el objeto QSortFilterProxyModel que utilizamos para filtrar las entradas, y tableView, el objeto QTableView.
Implementación de la clase AddressWidget
El constructor AddressWidget acepta un widget padre e instanciará NewAddressTab, TableModel y QSortFilterProxyModel. El objeto NewAddressTab, que se utiliza para indicar que la libreta de direcciones está vacía, se añade y el resto de las 9 pestañas se configuran con setupTabs().
AddressWidget::AddressWidget(QWidget *parent) : QTabWidget(parent), table(new TableModel(this)), newAddressTab(new NewAddressTab(this)) { connect(newAddressTab, &NewAddressTab::sendDetails, this, &AddressWidget::addEntry); addTab(newAddressTab, tr("Address Book")); setupTabs(); }
La función setupTabs() se utiliza para configurar las 9 pestañas del grupo alfabético, las vistas de tabla y los modelos proxy en AddressWidget. A su vez, cada modelo proxy se configura para filtrar los nombres de los contactos según el grupo alfabético correspondiente utilizando un objeto QRegularExpression que no distingue entre mayúsculas y minúsculas. Las vistas de tabla también se ordenan en orden ascendente utilizando la función sort() del modelo proxy correspondiente.
Cada vista de tabla selectionMode se establece en QAbstractItemView::SingleSelection y selectionBehavior se establece en QAbstractItemView::SelectRows, lo que permite al usuario seleccionar todos los elementos de una fila al mismo tiempo. A cada objeto QTableView se le asigna automáticamente un QItemSelectionModel que lleva la cuenta de los índices seleccionados.
void AddressWidget::setupTabs() { using namespace Qt::StringLiterals; const auto groups = { "ABC"_L1, "DEF"_L1, "GHI"_L1, "JKL"_L1, "MNO"_L1, "PQR"_L1, "STU"_L1, "VW"_L1, "XYZ"_L1 }; for (QLatin1StringView str : groups) { const auto regExp = QRegularExpression(QLatin1StringView("^[%1].*").arg(str), QRegularExpression::CaseInsensitiveOption); auto proxyModel = new QSortFilterProxyModel(this); proxyModel->setSourceModel(table); proxyModel->setFilterRegularExpression(regExp); proxyModel->setFilterKeyColumn(0); QTableView *tableView = new QTableView; tableView->setModel(proxyModel); tableView->setSelectionBehavior(QAbstractItemView::SelectRows); tableView->horizontalHeader()->setStretchLastSection(true); tableView->verticalHeader()->hide(); tableView->setEditTriggers(QAbstractItemView::NoEditTriggers); tableView->setSelectionMode(QAbstractItemView::SingleSelection); tableView->setSortingEnabled(true); connect(tableView->selectionModel(), &QItemSelectionModel::selectionChanged, this, &AddressWidget::selectionChanged); connect(this, &QTabWidget::currentChanged, this, [this, tableView](int tabIndex) { if (widget(tabIndex) == tableView) emit selectionChanged(tableView->selectionModel()->selection()); }); addTab(tableView, str); } }
La clase QItemSelectionModel proporciona una señal selectionChanged que se conecta a la señal selectionChanged() de AddressWidget. También conectamos la señal QTabWidget::currentChanged() a la expresión lambda que emite AddressWidget's selectionChanged() también. Estas conexiones son necesarias para activar las acciones Edit Entry... y Remove Entry en el menú Herramientas de MainWindow. Se explica con más detalle en la implementación de MainWindow.
Cada vista de tabla de la libreta de direcciones se añade como una pestaña a QTabWidget con la etiqueta correspondiente, obtenida de QStringList de grupos.

Proporcionamos dos funciones addEntry(): Una que está pensada para ser utilizada para aceptar entradas del usuario, y la otra que realiza la tarea real de añadir nuevas entradas a la libreta de direcciones. Dividimos la responsabilidad de añadir entradas en dos partes para permitir a newAddressTab insertar datos sin tener que abrir un cuadro de diálogo.
La primera función addEntry() es una ranura conectada a la acción MainWindow's Add Entry.... Esta función crea un objeto AddDialog y luego llama a la segunda función addEntry() para añadir realmente el contacto a table.
void AddressWidget::showAddEntryDialog() { AddDialog aDialog; if (aDialog.exec()) addEntry(aDialog.name(), aDialog.address()); }
En la segunda función addEntry() se realiza una validación básica para evitar entradas duplicadas en la libreta de direcciones. Como se mencionó con TableModel, esta es parte de la razón por la que necesitamos el método getter getContacts().
void AddressWidget::addEntry(const QString &name, const QString &address) { if (!name.front().isLetter()) { QMessageBox::information(this, tr("Invalid name"), tr("The name must start with a letter.")); } else if (!table->getContacts().contains({ name, address })) { table->insertRows(0, 1, QModelIndex()); QModelIndex index = table->index(0, 0, QModelIndex()); table->setData(index, name, Qt::EditRole); index = table->index(0, 1, QModelIndex()); table->setData(index, address, Qt::EditRole); removeTab(indexOf(newAddressTab)); } else { QMessageBox::information(this, tr("Duplicate Name"), tr("The name \"%1\" already exists.").arg(name)); } }
Si el modelo no contiene ya una entrada con el mismo nombre, llamamos a setData() para insertar el nombre y la dirección en la primera y segunda columnas. En caso contrario, mostramos un QMessageBox para informar al usuario.
Nota: El newAddressTab se elimina una vez que se añade un contacto, ya que la libreta de direcciones deja de estar vacía.
La edición de una entrada sólo permite actualizar la dirección del contacto, ya que el ejemplo no permite al usuario cambiar el nombre de un contacto existente.
En primer lugar, obtenemos el objeto QTableView de la pestaña activa mediante QTabWidget::currentWidget(). A continuación extraemos el selectionModel del tableView para obtener los índices seleccionados.
void AddressWidget::editEntry() { QTableView *temp = static_cast<QTableView*>(currentWidget()); QSortFilterProxyModel *proxy = static_cast<QSortFilterProxyModel*>(temp->model()); QItemSelectionModel *selectionModel = temp->selectionModel(); const QModelIndexList indexes = selectionModel->selectedRows(); QString name; QString address; int row = -1; for (const QModelIndex &index : indexes) { row = proxy->mapToSource(index).row(); QModelIndex nameIndex = table->index(row, 0, QModelIndex()); QVariant varName = table->data(nameIndex, Qt::DisplayRole); name = varName.toString(); QModelIndex addressIndex = table->index(row, 1, QModelIndex()); QVariant varAddr = table->data(addressIndex, Qt::DisplayRole); address = varAddr.toString(); }
A continuación, extraemos los datos de la fila que el usuario desea editar. Estos datos se muestran en una instancia de AddDialog con un título de ventana diferente. table sólo se actualiza si se han realizado cambios en los datos de aDialog.
AddDialog aDialog;
aDialog.setWindowTitle(tr("Edit a Contact"));
aDialog.editAddress(name, address);
if (aDialog.exec()) {
const QString newAddress = aDialog.address();
if (newAddress != address) {
const QModelIndex index = table->index(row, 1, QModelIndex());
table->setData(index, newAddress, Qt::EditRole);
}
}
}
Las entradas se eliminan utilizando la función removeEntry(). La fila seleccionada se elimina accediendo a ella a través del objeto QItemSelectionModel, selectionModel. La newAddressTab se vuelve a añadir a la AddressWidget sólo si el usuario elimina todos los contactos de la agenda.
void AddressWidget::removeEntry() { QTableView *temp = static_cast<QTableView*>(currentWidget()); QSortFilterProxyModel *proxy = static_cast<QSortFilterProxyModel*>(temp->model()); QItemSelectionModel *selectionModel = temp->selectionModel(); const QModelIndexList indexes = selectionModel->selectedRows(); for (QModelIndex index : indexes) { int row = proxy->mapToSource(index).row(); table->removeRows(row, 1, QModelIndex()); } if (table->rowCount(QModelIndex()) == 0) insertTab(0, newAddressTab, tr("Address Book")); }
La función writeToFile() se utiliza para guardar un archivo que contiene todos los contactos de la libreta de direcciones. El archivo se guarda en un formato personalizado de .dat. El contenido de la lista de contactos se escribe en file utilizando QDataStream. Si el archivo no puede abrirse, aparece un mensaje de error en QMessageBox.
void AddressWidget::writeToFile() { QFile file(fileName); if (!file.open(QIODevice::WriteOnly)) { QMessageBox::information(this, tr("Unable to open file"), file.errorString()); return; } QDataStream out(&file); out << table->getContacts(); }
La función readFromFile() carga un archivo que contiene todos los contactos de la libreta de direcciones, previamente guardados utilizando writeToFile(). QDataStream se utiliza para leer el contenido de un archivo .dat en una lista de contactos y cada uno de ellos se añade utilizando addEntry().
void AddressWidget::readFromFile() { QFile file(fileName); if (!file.open(QIODevice::ReadOnly)) { QMessageBox::information(this, tr("Unable to open file"), file.errorString()); return; } QList<Contact> contacts; QDataStream in(&file); in >> contacts; if (contacts.isEmpty()) { QMessageBox::information(this, tr("No contacts in file"), tr("The file you are attempting to open contains no contacts.")); } else { for (const auto &contact: std::as_const(contacts)) addEntry(contact.name, contact.address); } }
Definición de la clase NewAddressTab
La clase NewAddressTab proporciona una pestaña informativa que indica al usuario que la libreta de direcciones está vacía. Aparece y desaparece según el contenido de la libreta de direcciones, como se menciona en la implementación de AddressWidget.

La clase NewAddressTab extiende QWidget y contiene QLabel y QPushButton.
class NewAddressTab : public QWidget { Q_OBJECT public: NewAddressTab(QWidget *parent = nullptr); public slots: void addEntry(); signals: void sendDetails(const QString &name, const QString &address); };
Implementación de la clase NewAddressTab
El constructor instanciará addButton, descriptionLabel y conectará la señal de addButton a la ranura addEntry().
NewAddressTab::NewAddressTab(QWidget *parent) : QWidget(parent) { auto descriptionLabel = new QLabel(tr("There are currently no contacts in your address book. " "\nClick Add to add new contacts.")); auto addButton = new QPushButton(tr("Add")); connect(addButton, &QAbstractButton::clicked, this, &NewAddressTab::addEntry); auto mainLayout = new QVBoxLayout; mainLayout->addWidget(descriptionLabel); mainLayout->addWidget(addButton, 0, Qt::AlignCenter); setLayout(mainLayout); }
La función addEntry() es similar a AddressWidget's addEntry() en el sentido de que ambas funciones instancian un objeto AddDialog. Los datos del diálogo se extraen y se envían a la ranura addEntry() de AddressWidget emitiendo la señal sendDetails().
void NewAddressTab::addEntry() { AddDialog aDialog; if (aDialog.exec()) emit sendDetails(aDialog.name(), aDialog.address()); }

Definición de la clase AddDialog
La clase AddDialog extiende QDialog y proporciona al usuario un QLineEdit y un QTextEdit para introducir datos en la libreta de direcciones.
class AddDialog : public QDialog { Q_OBJECT public: AddDialog(QWidget *parent = nullptr); QString name() const; QString address() const; void editAddress(const QString &name, const QString &address); private: QLineEdit *nameText; QTextEdit *addressText; };

Implementación de la Clase AddDialog
El constructor AddDialog's configura la interfaz de usuario, creando los widgets necesarios y colocándolos en los diseños.
AddDialog::AddDialog(QWidget *parent) : QDialog(parent), nameText(new QLineEdit), addressText(new QTextEdit) { auto nameLabel = new QLabel(tr("Name")); auto addressLabel = new QLabel(tr("Address")); auto okButton = new QPushButton(tr("OK")); auto cancelButton = new QPushButton(tr("Cancel")); auto gLayout = new QGridLayout; gLayout->setColumnStretch(1, 2); gLayout->addWidget(nameLabel, 0, 0); gLayout->addWidget(nameText, 0, 1); gLayout->addWidget(addressLabel, 1, 0, Qt::AlignLeft|Qt::AlignTop); gLayout->addWidget(addressText, 1, 1, Qt::AlignLeft); auto buttonLayout = new QHBoxLayout; buttonLayout->addWidget(okButton); buttonLayout->addWidget(cancelButton); gLayout->addLayout(buttonLayout, 2, 1, Qt::AlignRight); auto mainLayout = new QVBoxLayout; mainLayout->addLayout(gLayout); setLayout(mainLayout); connect(okButton, &QAbstractButton::clicked, this, &QDialog::accept); connect(cancelButton, &QAbstractButton::clicked, this, &QDialog::reject); setWindowTitle(tr("Add a Contact")); } QString AddDialog::name() const { return nameText->text(); } QString AddDialog::address() const { return addressText->toPlainText(); } void AddDialog::editAddress(const QString &name, const QString &address) { nameText->setReadOnly(true); nameText->setText(name); addressText->setPlainText(address); }
Para dar al diálogo el comportamiento deseado, conectamos los botones OK y Cancel a las ranuras accept() y reject() del diálogo. Dado que el cuadro de diálogo sólo actúa como contenedor de información de nombres y direcciones, no necesitamos implementar ninguna otra función para él.
Definición de la clase MainWindow
La clase MainWindow extiende QMainWindow e implementa los menús y acciones necesarios para manipular la libreta de direcciones.
![]() | ![]() |
class MainWindow : public QMainWindow { Q_OBJECT public: MainWindow(); private slots: void updateActions(const QItemSelection &selection); void openFile(); void saveFile(); private: void createMenus(); AddressWidget *addressWidget; QAction *editAct; QAction *removeAct; };
La clase MainWindow utiliza un AddressWidget como widget central y proporciona el menú Archivo con las acciones Open, Close y Exit, así como el menú Tools con las acciones Add Entry..., Edit Entry... y Remove Entry.
Implementación de la clase MainWindow
El constructor de MainWindow instancia AddressWidget, lo establece como su widget central y llama a la función createMenus().
MainWindow::MainWindow() : QMainWindow(), addressWidget(new AddressWidget) { setCentralWidget(addressWidget); createMenus(); setWindowTitle(tr("Address Book")); }
La función createMenus() configura los menús File y Tools, conectando las acciones a sus respectivas ranuras. Las acciones Edit Entry... y Remove Entry están desactivadas por defecto, ya que no pueden llevarse a cabo en una libreta de direcciones vacía. Sólo se activan cuando se añaden uno o más contactos.
void MainWindow::createMenus() { QMenu *fileMenu = menuBar()->addMenu(tr("&File")); QAction *openAct = new QAction(tr("&Open..."), this); fileMenu->addAction(openAct); connect(openAct, &QAction::triggered, this, &MainWindow::openFile); ... editAct = new QAction(tr("&Edit Entry..."), this); editAct->setEnabled(false); toolMenu->addAction(editAct); connect(editAct, &QAction::triggered, addressWidget, &AddressWidget::editEntry); toolMenu->addSeparator(); removeAct = new QAction(tr("&Remove Entry"), this); removeAct->setEnabled(false); toolMenu->addAction(removeAct); connect(removeAct, &QAction::triggered, addressWidget, &AddressWidget::removeEntry); connect(addressWidget, &AddressWidget::selectionChanged, this, &MainWindow::updateActions); }
Además de conectar todas las señales de las acciones a sus respectivas ranuras, también conectamos la señal selectionChanged() de AddressWidget a su ranura updateActions().
La función openFile() abre un archivo personalizado addressbook.dat que contiene contactos de la libreta de direcciones. Esta función es una ranura conectada a openAct en el menú File.
void MainWindow::openFile() { addressWidget->readFromFile(); }
La función saveFile() guarda un archivo addressbook.dat personalizado que contendrá los contactos de la libreta de direcciones. Esta función es una ranura conectada a saveAct en el menú File.
void MainWindow::saveFile() { addressWidget->writeToFile(); }
La función updateActions() activa y desactiva Edit Entry... y Remove Entry en función del contenido de la libreta de direcciones. Si la libreta de direcciones está vacía, estas acciones se desactivan; en caso contrario, se activan. Esta función es una ranura está conectada a la señal AddressWidget's selectionChanged().
void MainWindow::updateActions(const QItemSelection &selection) { QModelIndexList indexes = selection.indexes(); if (!indexes.isEmpty()) { removeAct->setEnabled(true); editAct->setEnabled(true); } else { removeAct->setEnabled(false); editAct->setEnabled(false); } }
Función main()
La función main para la libreta de direcciones instanciará QApplication y abrirá un MainWindow antes de ejecutar el bucle de eventos.
int main(int argc, char *argv[]) { QApplication app(argc, argv); MainWindow mw; mw.show(); return app.exec(); }
© 2026 The Qt Company Ltd. Documentation contributions included herein are the copyrights of their respective owners. The documentation provided herein is licensed under the terms of the GNU Free Documentation License version 1.3 as published by the Free Software Foundation. Qt and respective logos are trademarks of The Qt Company Ltd. in Finland and/or other countries worldwide. All other trademarks are property of their respective owners.

