Qt window closes abruptally after changing dropdown option C++
-
Hi, I am new in Gt and am using it to learn and improve my skills in c++. I am develping a GUI to show database information. The window opens fine, but as soon as I try to change 'Source' on the dropdown menu, the window abruptally closes without showing errors.
What I've tried:
Add:blocksignals(true) code blocksignals(false)On the QObject::connect (connect signals),
replaced:QObject::connect(sourceCombo, &QComboBox::currentTextChanged, window, updateCategories); QObject::connect(categoryCombo, &QComboBox::currentTextChanged, window, updateSubjects); QObject::connect(subjectCombo, &QComboBox::currentTextChanged, window, updateDetails);For:
QObject::connect(sourceCombo, &QComboBox::currentTextChanged, sourceCombo, updateCategories); QObject::connect(categoryCombo, &QComboBox::currentTextChanged, sourceCombo, updateSubjects); QObject::connect(subjectCombo, &QComboBox::currentTextChanged, sourceCombo, updateDetails);dbwindow.h:
#include <QWidget> // Qt base class for all UI objects #include <QComboBox> // Qt widget for drop-down lists #include <QVBoxLayout> // Qt layout for vertical arrangement of widgets #include <QTextEdit> // Qt for text edit field #include <QStringList> // Qt container for lists of strings #include <QString> // Qt string class #include <QLabel> // Qt widget for text labels #include <QSet> // Qt container for text labels #include <vector> // Standard C++ vector container #include <iostream> struct Record { QString source; // Source name QString category; // Category name QString subject; // Subject name QString details; // Details text }; // Function to create and show the main window with dependent dropdowns inline QWidget* createDbWindow(const std::vector<Record>& records) { try { QWidget* window = new QWidget; // Create the main window widget QVBoxLayout* layout = new QVBoxLayout(window); // Create a vertical layout and set it for the window // Create dropdowns and text field QComboBox* sourceCombo = new QComboBox(window); // Dropdown for source QComboBox* categoryCombo = new QComboBox(window); // Dropdown for categories QComboBox* subjectCombo = new QComboBox(window); // Dropdown for subjects QTextEdit* detailsEdit = new QTextEdit(window); // Multi-line text field for details detailsEdit->setReadOnly(true); // Make details field read-only detailsEdit->setLineWrapMode(QTextEdit::WidgetWidth); // Enable line wrapping to fit the widget width // Collect unique source from records QSet<QString> sources; // Set to store unique brands for (const auto& rec : records) { sources.insert(rec.source); // Insert brand into set } sourceCombo->addItems(QStringList(sources.begin(), sources.end())); // Add sources to dropdown layout->addWidget(new QLabel("Source:", window)); // Add label for source layout->addWidget(sourceCombo); // Add source dropdown to layout layout->addWidget(new QLabel("Category:", window)); // Add label for category layout->addWidget(categoryCombo); // Add category dropdown to layout layout->addWidget(new QLabel("Subject:", window)); // Add label for subject layout->addWidget(subjectCombo); // Add subject dropdown to layout layout->addWidget(new QLabel("Details:", window)); // Add label for details layout->addWidget(detailsEdit); // Add details text field to layout // Helper function to update details field based on selected subject auto updateDetails = [&]() { QString selectedSource = sourceCombo->currentText(); // Get selected source QString selectedCategory = categoryCombo->currentText(); // Get selected category QString selectedSubject = subjectCombo->currentText(); // Get selected subject for (const auto& rec : records) { if (rec.source == selectedSource && rec.category == selectedCategory && rec.subject == selectedSubject) { detailsEdit->setText(rec.details); // Set details text for matching record return; } } detailsEdit->clear(); // Clear details if no match found }; // Helper function to update subject options based on selected category auto updateSubjects = [&]() { subjectCombo->blockSignals(true); subjectCombo->clear(); // Clear subject dropdown QSet<QString> subjects; // Set to store unique subjects QString selectedSource = sourceCombo->currentText(); // Get selected source QString selectedCategory = categoryCombo->currentText(); // Get selected category for (const auto& rec : records) { if (rec.source == selectedSource && rec.category == selectedCategory) // If record matches brand and category subjects.insert(rec.subject); // Insert subject into set } subjectCombo->addItems(QStringList(subjects.begin(), subjects.end())); // Add subjects to dropdown subjectCombo->blockSignals(false); // Re-enable signals updateDetails(); }; // Helper function to update category options based on selected source auto updateCategories = [&] () { categoryCombo->blockSignals(true); categoryCombo->clear(); // Clear category dropdown QSet<QString> categories; // Set to store unique categories QString selectedSource = sourceCombo->currentText(); // Get selected source for (const auto& rec: records) { if (rec.source == selectedSource) // If record matches selected brand categories.insert(rec.category); // Insert category into set } categoryCombo->addItems(QStringList(categories.begin(), categories.end())); // Add categories to dropdown categoryCombo->blockSignals(false); // Re-enable signals updateSubjects(); }; // Connect signals to update dropdowns and details when selection changes QObject::connect(sourceCombo, &QComboBox::currentTextChanged, window, updateCategories); // Update categories when source changes QObject::connect(categoryCombo, &QComboBox::currentTextChanged, window, updateSubjects); // Update subjects when category changes QObject::connect(subjectCombo, &QComboBox::currentTextChanged, window, updateDetails); // Update details when subject changes // Initialize dropdowns with first source selected if (sourceCombo->count() > 0) { sourceCombo->setCurrentIndex(0); // Select first source updateCategories(); // Update categories for initial source } window->setLayout(layout); // Set the layout for the window window->setWindowTitle("Database Viewer"); // Set the window title window->resize(755, 378); // Set window to 20 x 10 window->show(); // Show the window on the screen return window; } catch (const std::exception& e) { std::cerr << e.what() << "\n"; } } #endif //!DBWINDOW_Hdbacess.h:
#ifndef DBCONNECTION_WINDOW_H #define DBCONNECTION_WINDOW_H #include <pqxx/pqxx> #include <iostream> #include <vector> #include <string> // Structure to store each database record struct DataEntry { // Fields for 'source', 'category', 'subject' and 'details' column std::string source; std::string category; std::string subject; std::string details; }; // Function to open a connection to the PostgreSQL database inline pqxx::connection openDatabase() { // Connection string with db parameters (host, port, dbname, user, password) std::string conn_str = "host=localhost port=5432 dbname=prescreen_diag_data_api user=postgres password=shakey-10"; return pqxx::connection(conn_str); // Return a new pqxx connection object } // Function to fetch data from db inline std::vector<DataEntry> fetchData(pqxx::connection& conn) { std::vector<DataEntry> data; // Vector to store all fetched records try { pqxx::work txn(conn); // Start a transaction on the connection // Execute teh SQL query to select the desired columns pqxx::result res = txn.exec("SELECT source, category, subject, details FROM diagnostic_assistance_db;"); for (const auto& row : res) { // Create a new DataEntry struct DataEntry entry; // Assign each column value to the struct fields entry.source = row["source"].c_str(); entry.category = row["category"].c_str(); entry.subject = row["subject"].c_str(); entry.details = row["details"].c_str(); data.push_back(entry); // Add the entry to the vector } } catch (const std::exception& e) { std::cerr << "Error: " << e.what() << std::endl; } return data; // Return the vector with all records } #endif //!DBCONNECTION_WINDOW_Hmain.cpp
#include <QApplication> // Qt application class #include <QStringList> // For QStringList #include <pqxx/pqxx> #include "dbwindow.h" // For createDbWindow function #include "dbaccess.h" // For database access functions int main(int argc, char *argv[]) { try { QApplication app(argc, argv); // Create the Qt application pqxx::connection conn = openDatabase(); // Open database connection std::vector<DataEntry> data = fetchData(conn); // Fetch all data from the database std::vector<Record> records; // Vector to store all records for the GUI for (const auto& entry : data) { // Convert each DataEntry from the database to a Record for GUI records.push_back({ QString::fromStdString(entry.source), // Set source field QString::fromStdString(entry.category), // Set category field QString::fromStdString(entry.subject), // Set subject field QString::fromStdString(entry.details) // Set details field }); } QWidget* window = createDbWindow(records); // Create and show the window with dependent dropdowns return app.exec(); // Start the Qt event loop } catch(const std::exception& e) { std::cerr << e.what() << "\n"; } return 1; } -
Hi @weverson and welcome to the Qt forum!
Are you running this in a debugger?
Maybe add debug statements in theupdateSomething()lambdas.
The debugger of Qt Creator shows you where the program aborts (if it does).
My guess is that you still end up in an endless recursion and eventually the executable runs out of memory.
But that's hard to say, because the code is rather busy.
I'd recommend to drop all the try()ing. -
Hi Axel,
Thank you very much for your help. I forgot to mention some important details.
I am using VS code, so the debbuger is MSVC.
Also, I am executing the code on cmd after creating the build files through Cmake.@weverson
So you need to run/step through your code under the MSVC debugger. People don't know where in your hundreds of lines of code the issue lies. Not sure what your "Also, I am executing the code on cmd after creating the build files through Cmake." means, but as stated you need to run this under the debugger, not free running in some console window outside of debugger. Learning to debug with whatever debugger you use is the single most useful coding skill you will ever obtain, so it's worth spending some time to get familiar with it.