Open QWidget or QWindow from the current one - c++

I know this was asked here, but it doesn't work...
Here's my problem: my program actually has 2 forms: LoginWindow and MainWindow, the programme starts on LoginWindow and then I called a class Login where are all methods and attributes for checking users
Here's some code:
//in LoginWindow class
Login log;
log.checkID(ui->usrnmle->text().toStdString(), ui->passwdle->text().toStdString());
//in Login class
void Login::checkID(string usr, string passwd)
{
if(usr == "Test" && passwd == "root")
{
cout << "Ok!" << endl;
MainWindow mw = MainWindow();
mw.show();
LoginWindow lw = LoginWindow();
lw.hide();
}
else
{
cout << "Connection failed " << endl;
}
}
I type the good username and password, I got the 'Ok!' in the output console but MainWindow never appears.
Someone can help?

Your MainWindow mw is a local variable that is destroyed as soon as you are out of checkID function (or even out of if but that does not really matters)
You need to create it on heap
MainWindow *mw = new MainWindow();
mw->show();
Then to avoid memory leak you would need to destroy it when it is of no further use:
delete mw;

I'm not a QT developer, but
{
cout << "Ok!" << endl;
MainWindow mw = MainWindow();
mw.show();
LoginWindow lw = LoginWindow();
lw.hide();
}
You are creating two local windows here, which are destroyed on the spot when the scope ends.
you need to keep these instances alive throught their use. for example, make them member variables of some bigger object like "App" class os so.

Related

Problem when dereferencing std::unique_ptr with QT (Segmentation fault)

(Sorry for my future mistakes, I am fr)
I am creating a program to control the pc with a phone in c++ ( https://github.com/titicplusplus/PCPhone )
The server part works good, so I would like to add graphics interfaces for user, I decided to use QT.
When I stop the program QT, I have segmentation fault, and that stops the server.
My function that run the graphic interface:
void start_g(int argc, char **argv)
{
QApplication app(argc,argv);
QFile File(":/stylesheet.qss");
File.open(QFile::ReadOnly);
QString StyleSheet = QLatin1String(File.readAll());
app.setStyleSheet(StyleSheet);
ui interface; //QWidget window
interface.start();
std::cout << "start gui" << std::endl;
interface.show();
app.exec(); //return 0
return;
}
I encapsulated the code in a function because I would like to run it in a thread, but for now during my tests, I don't do this.
Here is my class ui (user interface)
class ui : public QWidget
{
public:
ui();
void start();
void change_file();
void change_port();
void freset();
void fapply();
~ui(); //Here is the problem
private:
openf f_open; //to open the extension s file
std::unique_ptr<QFormLayout> formLayout;
std::unique_ptr<QGroupBox> settings;
std::unique_ptr<QVBoxLayout> main_layout;
std::unique_ptr<QGridLayout> grid;
std::vector< std::vector< std::unique_ptr<QPushButton> > > tab2d;
std::unique_ptr<QGroupBox> all_button;
std::unique_ptr<QSpinBox> port_l;
std::unique_ptr<QPushButton> button_f;
std::unique_ptr<QPushButton> apply;
std::unique_ptr<QPushButton> reset;
std::unique_ptr<QLabel> text_f;
};
and the important function
ui::ui() {}
void ui::start()
{
grid = std::make_unique<QGridLayout>( this );
/** Code that you don't need, I guess **/
std::cout << "setting part" << std::endl;
all_button = std::make_unique<QGroupBox>("Slide");
all_button->setLayout(grid.get());
port_l =std::make_unique<QSpinBox>(this);
port_l->setMaximum(65535);
port_l->setValue( config_json["port"].get<int>() );
button_f = std::make_unique<QPushButton>("Open Image" ,this);
text_f = std::make_unique<QLabel>(QString::fromStdString(fs::absolute(config_json["image"].get<std::string>())), this);
apply = std::make_unique<QPushButton>(" Apply " ,this);
reset = std::make_unique<QPushButton>("Reset" ,this);
//connect(button_f.get(), &QPushButton::clicked, this, &ui::change_file);
connect(port_l.get(), QOverload<int>::of(&QSpinBox::valueChanged), this, &ui::change_port);
connect(apply.get(), &QPushButton::clicked, this, &ui::fapply);
connect(reset.get(), &QPushButton::clicked, this, &ui::freset);
//auto fileName = QFileDialog::getOpenFileName(&window, "Open Image", "/home/$USER", ("Image Files (*.png *.jpg *.bmp)"));
formLayout = std::make_unique<QFormLayout>();
formLayout->addRow("The port", port_l.get());
formLayout->addRow(text_f.get(), button_f.get()); //////////The problem is here
//formLayout->addRow(apply.get(), reset.get());
settings = std::make_unique<QGroupBox>("Settings");
settings->setLayout(formLayout.get());
main_layout = std::make_unique<QVBoxLayout>(this);
main_layout->addWidget(all_button.get());
main_layout->addWidget(settings.get());
}
So I saw on google, the problem come with the pointers and they destroy, so I try this
ui::~ui()
{
main_layout = nullptr;
settings = nullptr;
all_button = nullptr;
std::cout << "1u" << std::endl;
button_f = nullptr;
std::cout << "2u" << std::endl;
text_f = nullptr;
std::cout << "3u" << std::endl;
apply = nullptr;
std::cout << "4u" << std::endl;
reset = nullptr;
std::cout << "5u" << std::endl;
grid = nullptr;
std::cout << "bye bye" << std::endl;
}
The result is [ the errors are in french so I try to translate it ]:
1u
Segmentation fault (core dumped)
When I delete this line formLayout->addRow(text_f.get(), button_f.get());
There are no problems the deference of text_f and button_f, but with the next (apply and reset).
1u
2u
3u
Segmentation fault (core dumped)
On google, I saw a lot a time the people use the pointer and not the std::unique_ptr with qt, but I saw in general that people say "the smart pointer are better than the normal pointer.
Also, I try to replace button_f.get() to std::move(button_f).get() but that doesn't work.
For information, I am on Ubuntu 20.04, with g++-9.3 and qt5.
Thank you in advance for your answers !
Thanks G.M. and vahancho
I understand why I don't need to do std::unique_ptr .
When I learn C++ and pointer, there are rule : write one delete for every new, or better, use the smart pointer.
But with this two topics:
https://codereview.stackexchange.com/questions/43189/deleting-pointers-in-qt5/43201
Deleting Pointer to widget Qt C++
For the QT object, it's QT that deletes the pointers when the class is delete.
So I just need to need change all of my std::unique_ptr in raw pointer.

Why my C++ Qt UI got translated but not my QStrings in my program?

I needed to translate my english UI in french, so I did all the necessary with .ts and .qm files, load it in the QTranslator class, and install it to the QApplication:
//in the InterfaceWidget constructor:
QTranslator myappTranslator;
bool loaded = myappTranslator.load("myApp_" + QLocale::system().name());
qDebug() << "Is translation file loaded?" << loaded; // RETURNS TRUE
QApplication::installTranslator(&myappTranslator);
ui.setupUi(this);
ui.retranslateUi(this); //works, it translates the UI
Later, I create and attach to the InterfaceWidget another Widget (in a tab) called ConfigurationTabUI :
m_ConfigurationTabUI = new ConfigurationTabUI(ui.configTab);
The corresponding UI is also translated to french, correctly.
And here is my problem: in the ConfigurationTabUI's methods, it doesn't work when I try to translate a simple QString:
void ConfigurationTabUI::on_ValidButton_clicked(){
QString msg(ConfigurationTabUI::tr("message to translate"));
qDebug() << "translated string: " << msg; // NOT TRANSLATED
}
I really have no clue why...
Thanks for your help.
Note: I Use Qt5.2 and I double checked that the .ts file contains the right translated string.
Ok, I found the problem, it's just a dumb oversight:
QTranslator is created on the stack and not dynamically (on the heap), so the object is destroyed at the end of the method.
As a result, it translates the UI because the object is still there but later, when a slot is called, nothing get translated.
Here is my code:
//in the InterfaceWidget constructor:
QTranslator* myappTranslator = new QTranslator(QApplication::instance());
bool loaded = myappTranslator->load("myApp_" + QLocale::system().name());
qDebug() << "Is translation file loaded?" << loaded; // RETURNS TRUE
QApplication::installTranslator(myappTranslator);
ui.setupUi(this);
and in ConfigurationTabUI (which inherits from QWidget):
void ConfigurationTabUI::changeEvent(QEvent *e)
{
if (e->type() == QEvent::LanguageChange) {
ui.retranslateUi(this);
reset(); //my method to reload some data in UI
} else
QWidget::changeEvent(e);
}

Setting parent of a created qml object from C++ is not working

I have a C++ class that creates a QML object, it takes five parameters:
//prototype
// Q_INVOKABLE QQuickItem *createQmlObject(QObject *parent, QString path, QString id="", int x=0, int y=0);
QQuickItem * QmlItemCreator::createQmlObject(QObject* parent,QString path,QString id,int x,int y)
{
QQmlEngine engine;
QQmlComponent component(&engine, QUrl::fromLocalFile(path));
QQuickItem * mainObject_;
if(component.isError())
{
qWarning() << "QmlItemCreator::createQmlObject The QMLComponent for "
<< path << " has errors: " << component.errorString();
}
else if (component.isReady())
{
mainObject_ = qobject_cast<QQuickItem*>(component.create());
QQmlEngine::setObjectOwnership(mainObject_, QQmlEngine::JavaScriptOwnership);
mainObject_->setProperty("id",id);
mainObject_->setProperty("x",x);
mainObject_->setProperty("y",y);
mainObject_->setParent(parent);
// qDebug()<<mainObject_<<" "<<mainObject_->parent()<<" "<<mainObject_->property("x");
}
else
{
componentComplete();
}
return mainObject_;
}
I use it in QML as follows:
Item{
id: idRoot
Component.onCompleted:
{
var obj = qmlCreator.createQmlObject(idRoot,"path/test.qml")
console.log(obj.parent)// print null !!
}
}
While in C++ context, I can correctly print the value of the properties I set, as well as the parent of the created object. However, when I print them from QML, theparenthas anulland the properties areundefined`.
I printed the adress of the created object from C++ and from QML and I've got the same address. I don't understand what's causing this behaviour.
Thanks for your help.
I've solved the issue by adding the following line of code to the C++ code:
mainObject_->setParentItem(qobject_cast<QQuickItem*>(parent));

How to change window title and central widget in Qt?

Hi, I have a problem with changing window title and central widget in Qt.
There is MainWindow:
class MainWindow : public QMainWindow
{
// (...)
QStackedWidget* widgets;
Quiz* widget1, *widget2;
}
and there is a class Quiz:
class Quiz : public QWidget
{
public slots:
void myClicked();
}
I wanted to change MainWindow title after clicking on button, which is a element of Quiz (and it is connected with slot myClicked).
void Quiz::myClicked()
{
static_cast<MainWindow>(parent).myFunction();
}
void MainWindow::myFunction()
{
widget2 = new Quiz(this,2);
widgets->addWidget(widget2);
std::cout<<"current wdgt: " << widgets->currentIndex() << std::endl; // shows: 0
widgets->setCurrentWidget(widget2);
std::cout<<"current wdgt " << widgets->currentIndex() << std::endl; // shows: 1
setWindowTitle("newTitle");
std::cout<<"Title is " << windowTitle().toStdString() << std::endl;
}
So widgets->currentIndex shows index of new widget but nothing is changed in my window. The same problem is with window title - method windowTitle() returns new title, but title on a titlebar is old. Why?
If I change title in Quiz::myClicked by:
parent->setWindowTitle("newTitle");
it works! Why it works how strange? Please help.
it works! Why it works how strange? Please help.
It is not strange. That is how the Qt API is designed. See the documentation for the explanation:
windowTitle : QString
This property holds the window title (caption).
This property only makes sense for top-level widgets, such as windows and dialogs.
Let us analyze the last sentence: your quiz is neither a QMainWindow, nor a QDialog, hence it cannot work. Windows titles only make sense for those based on the documentation. When you call it on the parent, it will work respectively since that is a QMainWindow.
The title bar shows the title of the MainWindow. Your Quiz widgets are "inside" the MainWindow, so their titles are not shown.
If you want to change the title bar text, you must call MainWindow::setWindowTitle().

how can I make a connection to a database in the main function and then reference it from other functions

I have recently begun delving into the world that is database programming with C++ & Qt, and I've got a question. I know the answer is probably very basic but I can't seem to figure it out.
How can I make a connection to a database in the main function and then reference it from other functions?
Basically when the program first launches I create a instance of the main window, but before showing it, I connect to a database for later queries. I then show the window. Great but no when I try to make the window populate with data I can't because the connection name is outside of the scope of the function.
How could I make that global, I thought it would be by default because I have constructed the database in the main function witch every other class or function should inherit from(or at least I thought).
I'm still learning so I'm sure it is just a small misconception I have on how inheritance works.
Here is my main function
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MainWindow w;
QSqlDatabase db = QSqlDatabase::addDatabase("QODBC");
db.setHostName("LOCALHOST\\TestServer");
db.setDatabaseName("TestConnection");
w.show();
return a.exec();
}
And later on in the main window I create a dock which I can populate with data pulled from a database. Here is were I need to preform the Query in the mainwindow::Createdock function
void MainWindow::createDockWindows()
{
QDockWidget *rightDock = new QDockWidget(tr("Tasks"),this);
rightDock->setAllowedAreas(Qt::LeftDockWidgetArea | Qt::RightDockWidgetArea);
todoGroupBox = new QGroupBox(rightDock);
todoGroupBox->setTitle(tr("To-Do List"));
QSqlDatabase(db.open());
if (db.open())
{
QMessageBox::information(this,"Connected","Connection to the Database was Established\n"
"\nStatus: Connected");
}
else
{
QMessageBox::information(this,"Not Connected","Connection to the Database could not be Established\n"
"\nStatus: Not Connected");
}
todoList = new QListWidget(todoGroupBox);
todoList->addItems(QStringList()
<< "Install Outlook on Jessies Computer"
<< "Purchase 2 Licenses of Adobe Suite"
<< "Contact UPS to put in a ticket to their IT dept.");
addToDoLabel = new QLabel;
addToDoLabel->setText(tr("Sample Text"));
addToDoButton = new QToolButton;
addToDoButton->setIcon(QIcon(":/images/gedit-icon.png"));
addToDoButton->setToolTip(tr("Create a new task"));
addToDoButton->setShortcut(tr("Ctrl+Shift+t"));
QHBoxLayout *todoButtonLayout = new QHBoxLayout();
todoButtonLayout->addWidget(addToDoLabel,0,Qt::AlignRight | Qt::AlignVCenter);
todoButtonLayout->addWidget(addToDoButton,0,Qt::AlignRight | Qt::AlignTop);
QVBoxLayout *todoLayout = new QVBoxLayout();
todoLayout->addWidget(todoList,0,Qt::AlignCenter);
todoLayout->addLayout(todoButtonLayout,0);
todoGroupBox->setLayout(todoLayout);
todoGroupBox->setMaximumSize(todoGroupBox->sizeHint());
}
The simplest way of doing this in QT would be to name the database connection:
When you create add a database using QT you can call addDatabase() specifying a database connection name. When you do that you can in any class use database() and provide a database handle to the one you have created in main() or any other place in the code since both methods are static.
Example
db = QSqlDatabase::addDatabase("QODBC", "MyDB");
db.setDatabaseName("DRIVER={Microsoft Access Driver (*.mdb)};FIL={MS Access};DBQ=myaccessfile.mdb");
if (db.open()) {
// success!
}
Then anywhere in the code you can do:
QSqlDatabase localdb = QSqlDatabase::database("MyDB");
which will give you the handle to the one you have opened above.