Anropa andra klassers funktioner med argument inom C++ QT?

Permalänk

Anropa andra klassers funktioner med argument inom C++ QT?

Låt oss säga att vi har en funktion inom C++ QT som heter

void Main_window::on_actionInput_calibration_triggered(){ main_terminal_append_status_row("Input calibration menu button pressed"); input_calibration = new Input_calibration(); input_calibration->show(); }

När on_actionInput_calibration_triggered() anropas så öppnas ett nytt fönster upp.

I klassen Input_calibration som ser ut så här

Input_calibration::Input_calibration(QWidget *parent) : QWidget(parent), ui(new Ui::Input_calibration) { ui->setupUi(this); } Input_calibration::~Input_calibration(){ delete ui; } void Input_calibration::on_refrensh_calibrations_pushButton_clicked(){ }

Då finns det en funktion vid namn on_refrensh_calibrations_pushButton_clicked() som är kopplad till en knapp på mitt grafiska gränssnitt.

Målet med detta är att öva på att ha kommunikation mellan olika klasser inom C++ QT. Det jag vill göra är att när jag trycker på knappen så anropas on_refrensh_calibrations_pushButton_clicked() och då vill jag att denna funktion ska köras.

void Main_window::main_terminal_append_status_row(const QString& status){ QString line = dateTime.currentDateTime().toLocalTime().toString() + " : " + status; if(collected_status_text_line_in_main_terminal.length() > MAX_ROWS_IN_MAIN_TERMINAL){ collected_status_text_line_in_main_terminal.removeFirst(); collected_status_text_line_in_main_terminal.append(line); ui->main_terminal_textEdit->clear(); foreach(QString str, collected_status_text_line_in_main_terminal) ui->main_terminal_textEdit->append(str); }else{ ui->main_terminal_textEdit->append(line); collected_status_text_line_in_main_terminal.append(line); } }

Det finns flera sätt att göra detta. Antingen så använder jag nyckelordet this som argument. Se pil <----

void Main_window::on_actionInput_calibration_triggered(){ main_terminal_append_status_row("Input calibration menu button pressed"); input_calibration = new Input_calibration(this); <---- input_calibration->show(); }

Och sedan så anropar jag main_terminal_append_status_row(const QString& status) från funktionen on_refrensh_calibrations_pushButton_clicked().

Men detta är liksom standard C++ metodik. Att använda objekt i klasser som argument i konstruktörer kan vara rätt bökigt om det grenar sig allt för djupt. Nu kör jag QT ramverket och tanken är att man ska använda något som heter connect inom QT, vilket sägs ska göra livet enklare.

Jag har använt connect förut och det är bra. Men det var vid unika fall med färdiga klasser och färdiga exempel. Nu vill jag använda connect för att enkelt kunna anropa andra klassers funktioner med argument. Hur kan jag göra det?

Förslag:

Tycker ni att jag borde sätta en signal så här

class Input_calibration : public QWidget { Q_OBJECT public: explicit Input_calibration(QWidget *parent = nullptr); ~Input_calibration(); signals: void main_terminal_append_status_row(const QString& status);

Där jag anropar main_terminal_append_status_row med koden

emit main_terminal_append_status_row("Refresh calibration button pressed");

och jag ansluter klasserna med

input_calibration = new Input_calibration(); input_calibration->show(); connect(input_calibration, &Input_calibration::main_terminal_append_status_row, this, &Main_window::main_terminal_append_status_row);

Vad tycker ni?

Permalänk
Hedersmedlem
Skrivet av heretic16:

Vad tycker ni?

Kör med connect! Det gör programmets beståndsdelar mer modulära och löser även kommunikation mellan trådar automagiskt (typiskt när man vill ändra användargränssnittet från en bakgrundstråd). Glöm inte heller att man kan skicka med lambdafunktioner till connect och att den grafiska gui-editorn är väldigt behändig.

Permalänk
Skrivet av Elgot:

Kör med connect! Det gör programmets beståndsdelar mer modulära och löser även kommunikation mellan trådar automagiskt (typiskt när man vill ändra användargränssnittet från en bakgrundstråd). Glöm inte heller att man kan skicka med lambdafunktioner till connect och att den grafiska gui-editorn är väldigt behändig.

Du menar att jag behöver inte skriva denna kod i min konstruktör? Jag kan göra allt grafiskt?
Eller tänker du på slots och signals nu för GUI? Detta använder jag hela tiden. Alltså jag högerklicka och sedan ger den en slot så det blir C++ kod.

Hur som helst så har jag skrivit denna kod i min konstruktör för Main_Window. Bara för att vissa "under-klasser" ska ha anslutning med en viss funktion från Main_Window. Bökigt.

/* Connections */ connect(database_connect, &Database_connect::main_terminal_append_status_row, this, &Main_window::main_terminal_append_status_row); connect(usb_connect, &Usb_connect::main_terminal_append_status_row, this, &Main_window::main_terminal_append_status_row); connect(input_calibration, &Input_calibration::main_terminal_append_status_row, this, &Main_window::main_terminal_append_status_row);

Tror du jag kan använda connect som någon dependency injection?
Jag har behov utav att en klass som heter Database.cpp ska finnas tillgänglig i flera andra .cpp filer. Istället för att initialisera objekt i konstruktören för klass efter klass efter klass efter klass efter klass efter klass efter klass efter klass efter klass med mera klasser.

Då borde jag bara kunna använda emit för att anropa klassen's funktioner? Eller hur?
Det är svårt för mig att förklara. Men du känner säkert till scenariot där man vill att ett objekt ska vara tillgänglig på flera ställen av koden och objektet ska dela samma minne. Istället för att programmera massa kod t.ex. fylla konstruktörer med massa objekt-argument. Då använder man dependency injection som sköter allt detta åt en.

Men hur gör men detta i QT? Kan jag använda connect för det?

Permalänk
Hedersmedlem
Skrivet av heretic16:

Du menar att jag behöver inte skriva denna kod i min konstruktör? Jag kan göra allt grafiskt?
Eller tänker du på slots och signals nu för GUI? Detta använder jag hela tiden. Alltså jag högerklicka och sedan ger den en slot så det blir C++ kod.

Det var mest det senare jag tänkte på (somliga skriver allt för hand), men det finns också grafiskt stöd för connect (även om den kanske mest är lämplig för enklare relationer mellan kontroller):

Skrivet av heretic16:

Tror du jag kan använda connect som någon dependency injection?
Jag har behov utav att en klass som heter Database.cpp ska finnas tillgänglig i flera andra .cpp filer. Istället för att initialisera objekt i konstruktören för klass efter klass efter klass efter klass efter klass efter klass efter klass efter klass efter klass med mera klasser.

Då borde jag bara kunna använda emit för att anropa klassen's funktioner? Eller hur?
Det är svårt för mig att förklara. Men du känner säkert till scenariot där man vill att ett objekt ska vara tillgänglig på flera ställen av koden och objektet ska dela samma minne. Istället för att programmera massa kod t.ex. fylla konstruktörer med massa objekt-argument. Då använder man dependency injection som sköter allt detta åt en.

Men hur gör men detta i QT? Kan jag använda connect för det?

Ja, just just att anropa en funktion i ett annat objekt (eventuellt med parametrar) är ju precis vad connect gör, så det borde fungera.
Det finns även några andra varianter på connect:
"gamla" stilen (mindre typsäker, men ibland enklare):

connect(database_connect, SIGNAL(main_terminal_append_status_row()), this, SLOT(main_terminal_append_status_row()));

lambda-varianten:

connect(database_connect, &Database_connect::main_terminal_append_status_row, [=]() { main_terminal_append_status_row(); });

Permalänk
Skrivet av Elgot:

Det var mest det senare jag tänkte på (somliga skriver allt för hand), men det finns också grafiskt stöd för connect (även om den kanske mest är lämplig för enklare relationer mellan kontroller):
https://i.imgur.com/7QRxaxs.png

Ja, denna känner jag igen. Men jag har inte använt den då jag har sällan behov att skicka värden mellan olika komponenter i en gemensam kontroller.

Jag har snarare behov utav att skicka värden mellan olika kontrollers. Vi säger att vi har ett grafiskt gränsnitt som lyder:
Main Window -> Database Connect -> Database Handler

Där Database Handler är klassen som håller i allt det där med databasen ska göra. Läsa, skriva, ansluta, radera med mera.

Sedan har vi:
Main Window -> Analyse Data -> Database Handler

Där Analyse Data ska använda sig av andra funktioner i Database Handler. Detta är vad jag tycker är problem med C++ och många andra språk. Jag vill att Database Handler skall finnas i både Analyse Data och Database Connect, utan att jag behöver initialisera ett Database Handler objekt i varje konstruktör på den klass som ska använda Database Handler.

Inom Spring Boot (Java) så använder man @Autowired på ett fält inom dessa olika klasser och vipps så är detta fält deklarerad och färdig. Superenkelt! Här har verkligen Spring Boot tänkt rätt.

Citat:

Ja, just just att anropa en funktion i ett annat objekt (eventuellt med parametrar) är ju precis vad connect gör, så det borde fungera.
Det finns även några andra varianter på connect:
"gamla" stilen (mindre typsäker, men ibland enklare):

connect(database_connect, SIGNAL(main_terminal_append_status_row()), this, SLOT(main_terminal_append_status_row()));

Att använda SIGNAL och SLOT är den gamla stilen. Den finns fortfarande, men QT rekommenderar att skriva

connect(signal_klassen, &Signal_klassen::din_signal_funktion, slot_klassen, &Slot_klassen::din_slot_funktion);

I detta fall behöver din_slot_funktion bara vara en vanlig funktion inom klassen Slot_klassen, medan din_signal_funktion behöver deklareras som en publik signal i header-filen. Den anropas via emit.

Citat:

lambda-varianten:

connect(database_connect, &Database_connect::main_terminal_append_status_row, [=]() { main_terminal_append_status_row(); });

Så syftet med lambdavarianten är att jag kan utföra flera funktioner från en signal? Låter bra enligt mig. Detta ska jag använda.

Permalänk
Hedersmedlem
Skrivet av heretic16:

Jag har snarare behov utav att skicka värden mellan olika kontrollers. Vi säger att vi har ett grafiskt gränsnitt som lyder:
Main Window -> Database Connect -> Database Handler

Där Database Handler är klassen som håller i allt det där med databasen ska göra. Läsa, skriva, ansluta, radera med mera.

Sedan har vi:
Main Window -> Analyse Data -> Database Handler

Där Analyse Data ska använda sig av andra funktioner i Database Handler. Detta är vad jag tycker är problem med C++ och många andra språk. Jag vill att Database Handler skall finnas i både Analyse Data och Database Connect, utan att jag behöver initialisera ett Database Handler objekt i varje konstruktör på den klass som ska använda Database Handler.

Inom Spring Boot (Java) så använder man @Autowired på ett fält inom dessa olika klasser och vipps så är detta fält deklarerad och färdig. Superenkelt! Här har verkligen Spring Boot tänkt rätt.

Kan du inte använda någon singleton eller så?

Skrivet av heretic16:

Så syftet med lambdavarianten är att jag kan utföra flera funktioner från en signal? Låter bra enligt mig. Detta ska jag använda.

Det är ett väldigt generellt sätt att köra lite godtycklig kod utan att behöva skriva "vanliga" funktioner, men det kan till exempel användas så. Eller för att anropa en funktion som inte är en slot.

Permalänk
Skrivet av Elgot:

Kan du inte använda någon singleton eller så?

Hur menar du? Jag har hört talas som singelton, men aldrig kunna placera det.

Citat:

Det är ett väldigt generellt sätt att köra lite godtycklig kod utan att behöva skriva "vanliga" funktioner, men det kan till exempel användas så. Eller för att anropa en funktion som inte är en slot.

Ja. Detta är vad jag gör.

Permalänk
Hedersmedlem
Skrivet av heretic16:

Hur menar du? Jag har hört talas som singelton, men aldrig kunna placera det.

Som en glorifierad global variabel, till exempel realiserad som en statisk medlem i en klass. I ditt fall skulle kanske
DatabaseHandler::instance
kunna vara en statisk instans som kan användas på alla ställen.

Permalänk
Skrivet av Elgot:

Som en glorifierad global variabel, till exempel realiserad som en statisk medlem i en klass. I ditt fall skulle kanske
DatabaseHandler::instance
kunna vara en statisk instans som kan användas på alla ställen.

Så om jag använder Database_handler klassen som har ett statiskt objekt t.ex QTDatabase() och gör den statisk så jag kan anropa en funktion från Database_handler som ger mig full tillgång till QTDatabase()?

Permalänk
Hedersmedlem
Skrivet av heretic16:

Så om jag använder Database_handler klassen som har ett statiskt objekt t.ex QTDatabase() och gör den statisk så jag kan anropa en funktion från Database_handler som ger mig full tillgång till QTDatabase()?

Det borde väl vara lika smidigt som autowire, men det har ju ungefär samma nackdelar som globala variabler (fast det gäller väl autowire också).

Permalänk
Skrivet av Elgot:

Det borde väl vara lika smidigt som autowire, men det har ju ungefär samma nackdelar som globala variabler (fast det gäller väl autowire också).

Men om jag vill att Datbase_handler ska retunera ett statiskt objekt så borde statiskt varar rätt bra i detta tillfälle?

Har du någon C++ kod som du kan visa på singelton?

Permalänk
Hedersmedlem
Skrivet av heretic16:

Men om jag vill att Datbase_handler ska retunera ett statiskt objekt så borde statiskt varar rätt bra i detta tillfälle?

Jag bara reserverar mig för att man alltid kommer få kritik om man föreslår en lösning som involverar globala variabler (eller goto), men om fördelarna är större än nackdelarna borde det vara en fungerade lösning.

Skrivet av heretic16:

Har du någon C++ kod som du kan visa på singelton?

Jag har inget eget på rak arm, men konceptet är ju inte jätteavancerat. Här (i slutet av tråden alltså) ges exempel på en template-baserad singleton-klass som verkar vettig.

Permalänk
Skrivet av Elgot:

Jag bara reserverar mig för att man alltid kommer få kritik om man föreslår en lösning som involverar globala variabler (eller goto), men om fördelarna är större än nackdelarna borde det vara en fungerade lösning.

Jag har inget eget på rak arm, men konceptet är ju inte jätteavancerat. Här (i slutet av tråden alltså) ges exempel på en template-baserad singleton-klass som verkar vettig.

Jag tror jag har hamnat delvis rätt i mitt tänk, men jag får ett error.

Felet är och jag förstår inte varför? Hur kan jag missa referensen till instance? Den är ju deklarerad redan som en pekare?
(Du får gärna påpeka något hur jag deklarerar datatyper för SQL kolumnerna. Jag använder nämligen int[] och enums för att indexera)

application\tools\communication\database\database.cpp:-1: error: undefined reference to `Database::instance'

Här är min header

/* QT includes */ #include <QSqlDatabase> #include <QStringList> enum{ MY_SQL_BOOL, MY_SQL_TINYINT, MY_SQL_SMALLINT, MY_SQL_INT, MY_SQL_BIGINT, MY_SQL_FLOAT, MY_SQL_VARCHAR255, MY_SQL_DATETIME }; typedef enum{ DATABASE_STATUS_OK, DATABASE_STATUS_NOT_CONNECTED, DATABASE_STATUS_EXISTING_ROW, DATABASE_STATUS_COULD_NOT_INSERT_ROW }DATABASE_STATUS; /* Measurement columns */ const static QString MEASUREMENT_TABLE_NAME = "measurement_table"; const static QStringList MEASUREMENT_COLUMNS = {"ID", "logging_id", "calibration_id", "logging_comment", "measurement_date_time","ADC0","ADC1","ADC2","ADC3","ADC4","ADC5","ADC6","ADC7","ADC8","ADC9","ADC10","ADC11","DADC0","DADC1","DADC2","DADC3","DADC4","I0","I1","I2","I3","I4","I5","I6","I7","E0","E1","IC0","IC1","DAC0","DAC1","DAC2","PWM0","PWM1","PWM2","PWM3","PWM4","PWM5","PWM6","PWM7"}; const static int MEASUREMENT_DATA_TYPES[] = {MY_SQL_BIGINT, MY_SQL_INT, MY_SQL_INT, MY_SQL_VARCHAR255, MY_SQL_DATETIME, MY_SQL_FLOAT, MY_SQL_FLOAT, MY_SQL_FLOAT, MY_SQL_FLOAT, MY_SQL_FLOAT, MY_SQL_FLOAT, MY_SQL_FLOAT, MY_SQL_FLOAT, MY_SQL_FLOAT, MY_SQL_FLOAT, MY_SQL_FLOAT, MY_SQL_FLOAT, MY_SQL_FLOAT, MY_SQL_FLOAT, MY_SQL_FLOAT, MY_SQL_FLOAT, MY_SQL_FLOAT, MY_SQL_FLOAT, MY_SQL_BOOL, MY_SQL_BOOL, MY_SQL_BOOL, MY_SQL_BOOL, MY_SQL_BOOL, MY_SQL_BOOL, MY_SQL_BOOL, MY_SQL_BOOL, MY_SQL_FLOAT, MY_SQL_FLOAT, MY_SQL_FLOAT, MY_SQL_FLOAT, MY_SQL_SMALLINT, MY_SQL_SMALLINT, MY_SQL_SMALLINT, MY_SQL_SMALLINT, MY_SQL_SMALLINT, MY_SQL_SMALLINT, MY_SQL_SMALLINT, MY_SQL_SMALLINT, MY_SQL_SMALLINT, MY_SQL_SMALLINT, MY_SQL_SMALLINT}; /* Calibration columns */ const static QString CALIBRATION_TABLE_NAME = "calibration_table"; const static QStringList CALIBRATION_COLUMNS = {"ID", "calibration_id", "calibration_comment", "calibration_date_time", "min_adc0", "max_adc0", "bias_adc0", "min_adc1", "max_adc1", "bias_adc1", "min_adc2", "max_adc2", "bias_adc2", "min_adc3", "max_adc3", "bias_adc3", "min_adc4", "max_adc4", "bias_adc4", "min_adc5", "max_adc5", "bias_adc5", "min_adc6", "max_adc6", "bias_adc6", "min_adc7", "max_adc7", "bias_adc7", "min_adc8", "max_adc8", "bias_adc8", "min_adc9", "max_adc9", "bias_adc9", "min_adc10", "max_adc10", "bias_adc10", "min_adc11", "max_adc11", "bias_adc11", "min_dadc0", "max_dadc0", "bias_dadc0", "min_dadc1", "max_dadc1", "bias_dadc1", "min_dadc2", "max_dadc2", "bias_dadc2", "min_dadc3", "max_dadc3", "bias_dadc3", "min_dadc4", "max_dadc4", "bias_dadc4", "pulses_per_revolution_encoder0", "pulses_per_revolution_encoder1"}; const static int CALIBRATION_DATA_TYPES[] = {MY_SQL_BIGINT, MY_SQL_INT, MY_SQL_VARCHAR255, MY_SQL_DATETIME, MY_SQL_FLOAT, MY_SQL_FLOAT, MY_SQL_FLOAT, MY_SQL_FLOAT, MY_SQL_FLOAT, MY_SQL_FLOAT, MY_SQL_FLOAT, MY_SQL_FLOAT, MY_SQL_FLOAT, MY_SQL_FLOAT, MY_SQL_FLOAT, MY_SQL_FLOAT, MY_SQL_FLOAT, MY_SQL_FLOAT, MY_SQL_FLOAT, MY_SQL_FLOAT, MY_SQL_FLOAT, MY_SQL_FLOAT, MY_SQL_FLOAT, MY_SQL_FLOAT, MY_SQL_FLOAT, MY_SQL_FLOAT, MY_SQL_FLOAT, MY_SQL_FLOAT, MY_SQL_FLOAT, MY_SQL_FLOAT, MY_SQL_FLOAT, MY_SQL_FLOAT, MY_SQL_FLOAT, MY_SQL_FLOAT, MY_SQL_FLOAT, MY_SQL_FLOAT, MY_SQL_FLOAT, MY_SQL_FLOAT, MY_SQL_FLOAT, MY_SQL_FLOAT, MY_SQL_FLOAT, MY_SQL_FLOAT, MY_SQL_FLOAT, MY_SQL_FLOAT, MY_SQL_FLOAT, MY_SQL_FLOAT, MY_SQL_FLOAT, MY_SQL_FLOAT, MY_SQL_FLOAT, MY_SQL_FLOAT, MY_SQL_FLOAT, MY_SQL_FLOAT, MY_SQL_FLOAT, MY_SQL_FLOAT, MY_SQL_FLOAT, MY_SQL_SMALLINT, MY_SQL_SMALLINT}; class Database { public: static bool connect_to_database(const QString& hostname, const QString& databaseName, const int port, const QString& username, const QString& password); static void create_a_table_if_not_exist(const QString &table_name, const QStringList& columns, const int data_types[]); static void close_connection(); static bool is_open(); private: /* Constructor fields */ Database(QSqlDatabase& qSqlDatabase); /* Instance */ static Database* getInstance(); static Database* instance; /* Objects */ QSqlDatabase qSqlDatabase; };

Här är min källfil

#include "database.h" /* QT includes */ #include <QMessageBox> #include <QSqlQuery> Database::Database(QSqlDatabase& qSqlDatabase){ this->qSqlDatabase = qSqlDatabase; } Database* Database::getInstance(){ if (instance == NULL){ /* First time, add the object to the Database class */ const QString SQL = "QMYSQL"; QSqlDatabase qSqlDatabase = QSqlDatabase::addDatabase(SQL); if(!qSqlDatabase.isDriverAvailable(SQL)) QMessageBox::information(nullptr, "SQL driver", "Driver " + SQL + " is missing", QMessageBox::Ok); instance = new Database(qSqlDatabase); } return instance; } bool Database::connect_to_database(const QString& hostname, const QString& databaseName, const int port, const QString& username, const QString& password){ Database* inst = getInstance()->instance; inst->qSqlDatabase.setHostName(hostname); inst->qSqlDatabase.setDatabaseName(databaseName); inst->qSqlDatabase.setPort(port); inst->qSqlDatabase.setUserName(username); inst->qSqlDatabase.setPassword(password); return inst->qSqlDatabase.open(); } void Database::create_a_table_if_not_exist(const QString &table_name, const QStringList& columns, const int data_types[]){ QSqlQuery query; /* Create the table if it's not existing */ query.exec("CREATE TABLE " + table_name + "(" + columns[0] + " BIGINT NOT NULL AUTO_INCREMENT PRIMARY KEY)"); /* Import columns, if they don't existing */ for(int i = 1; i < columns.length(); i++){ QString data_type = ""; switch (data_types[i]) { case MY_SQL_BOOL: data_type = "BOOL"; /* True or false */ break; case MY_SQL_TINYINT: data_type = "TINYINT"; /* 8-bit */ break; case MY_SQL_SMALLINT: data_type = "SMALLINT"; /* 16-bit */ break; case MY_SQL_INT: data_type = "INT"; /* 32-bit */ break; case MY_SQL_BIGINT: data_type = "BIGINT"; /* 64-bit */ break; case MY_SQL_FLOAT: data_type = "FLOAT"; /* 32-bit */ break; case MY_SQL_VARCHAR255: data_type = "VARCHAR(255)"; /* String */ break; case MY_SQL_DATETIME: data_type = "DATETIME"; /* Date time */ break; } /* If column already exist, exec function return false */ query.exec("ALTER TABLE " + table_name + " ADD " + columns[i] + " " + data_type); } } void Database::close_connection(){ getInstance()->qSqlDatabase.close(); } bool Database::is_open(){ return getInstance()->qSqlDatabase.isOpen(); }

Permalänk
Hedersmedlem
Skrivet av heretic16:

Jag tror jag har hamnat delvis rätt i mitt tänk, men jag får ett error.

Felet är och jag förstår inte varför? Hur kan jag missa referensen till instance? Den är ju deklarerad redan som en pekare?

Det där är en klassisk egenhet med statiska klassmedlemmar; de måste definieras någonstans utanför klassen. Testa att lägga till

Database* Database::instance;

någonstans (till exempel i din cpp-fil):

#include <QSqlQuery> Database* Database::instance; Database::Database(QSqlDatabase& qSqlDatabase){ this->qSqlDatabase = qSqlDatabase; }

Skrivet av heretic16:

(Du får gärna påpeka något hur jag deklarerar datatyper för SQL kolumnerna. Jag använder nämligen int[] och enums för att indexera)

Det känns som att du får skriva ut datatyperna fler gånger än nödvändigt (enum + switch). Man skulle kanske kunna tänka sig en QMap<int, QString> med id och datatyp som man sedan kan slå upp i (eller helt enkelt ha en lista med datatyper och plocka ut element data_types[i]).

Permalänk
Skrivet av Elgot:

Det där är en klassisk egenhet med statiska klassmedlemmar; de måste definieras någonstans utanför klassen. Testa att lägga till

Database* Database::instance;

någonstans (till exempel i din cpp-fil):

#include <QSqlQuery> Database* Database::instance; Database::Database(QSqlDatabase& qSqlDatabase){ this->qSqlDatabase = qSqlDatabase; }

Det känns som att du får skriva ut datatyperna fler gånger än nödvändigt (enum + switch). Man skulle kanske kunna tänka sig en QMap<int, QString> med id och datatyp som man sedan kan slå upp i (eller helt enkelt ha en lista med datatyper och plocka ut element data_types[i]).

Tack! Nu fungerar det.

QMap och QHash är rätt dåliga verktyg enligt min mening då dom är svåra att jobba med. Svåra att indexera korrekt.

Värsta är Set() klassen i Java. Måste vara det sämsta som finns inom Java. Men det är en annat språk

Permalänk
Hedersmedlem
Skrivet av heretic16:

QMap och QHash är rätt dåliga verktyg enligt min mening då dom är svåra att jobba med. Svåra att indexera korrekt.

De har ju lite speciella användningsområden, men just för att avbilda en mängd på en annan är de ju väldigt smidiga.

Skrivet av heretic16:

Värsta är Set() klassen i Java. Måste vara det sämsta som finns inom Java. Men det är en annat språk

Dess främsta förmåga är väl att hyfsat effektivt filtrera bort dubbletter?

Permalänk
Skrivet av Elgot:

De har ju lite speciella användningsområden, men just för att avbilda en mängd på en annan är de ju väldigt smidiga.

Dess främsta förmåga är väl att hyfsat effektivt filtrera bort dubbletter?

Jag löste detta med. Ungefär som QMap men man väljer själv indexeringen. Nu fungerar allt Tackar så mycket.

Men varför behöver jag denna?

Database* Database::instance;

När jag redan har detta

private: /* Constructor fields */ Database(QSqlDatabase& qSqlDatabase); /* Instance */ static Database* getInstance(); static Database* instance;

QVector<QPair<QString, int>

Jag har bara använt Set när det kommer till databaser där Spring JPA används. Set är rent av hemskt. Bara krångligt.