i want to build a QT application for windows/android.
I have one mainwindow in which i have different buttons to call submenus, as you can see on the pictures. What do you think is the best implementation for that?
I thought about replacing the central widget
Using QStackwidget
Or open a new widget on the same position and size and close after.
What do you think? Do you have some favourite implementation or do i miss some important?
Edit
My Mainwindow constructor
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
m_stacked = new QStackedWidget;
HomeScreen *homescreen=new HomeScreen(m_stacked);
Control *manual=new Control(m_stacked);
m_stacked->addWidget(homescreen);
m_stacked->addWidget(manual);
this->setCentralWidget(m_stacked);
}
Implementation of every Screen
class HomeScreen : public QWidget
{
Q_OBJECT
public:
explicit HomeScreen(QStackedWidget* stack, QWidget *parent = 0);
~HomeScreen();
private slots:
void on_pushButton_clicked();
private:
Ui::HomeScreen *ui;
QStackedWidget *m_stacks;
};
HomeScreen::HomeScreen(QStackedWidget* stack,QWidget *parent) :
m_stacks(stack),QWidget(parent),
ui(new Ui::HomeScreen)
{
ui->setupUi(this);
}
HomeScreen::~HomeScreen()
{
delete ui;
}
void HomeScreen::on_pushButton_clicked()
{
m_stacks->setCurrentIndex(1);
}
What is your solution to change the current Widget, inside a widget of the QStackwidget? I used the solution above what do you think about it?
QStackedWidget was made right for that, I don't see any reason why you should incline to other options. You can always removeWidget(widget) and delete widget; if you want to free the memory of some rarely used menu.
Edit:
Your code is fine, there can be only a few enhancements made. You can create enum for your indexes in some separate header file.
Option 1:
If you use only QStackedWidget as a parent menu, you can adjust the constructor:
HomeScreen(QStackedWidget* parent) :
QWidget(parent),
ui(new Ui::HomeScreen)
{
ui->setupUi(this);
}
If you'd want to access QStackedWidget and change an index, you spare m_stacks pointer and use the parent: dynamic_cast<QStackedWidget*>(parent())->setCurrentIndex(1 /* or enum */);.
Option 2:
Leave index changing to the parent MainWindow. Each menu will have a request signal:
signals:
void goToMenuRequest(int index /* or enum */);
which you connect to m_stacked's setCurrentIndex in the constructor of MainWindow.
Not a big things, but It'll make coding easier.
Related
I have been trying to add a QToolBar inside a QTabWidget in order to achieve something like the image below, so that everytime I add a new QTabWidget I have also a related QToolBar inside it.
Everything seems to work fine, I create a QAction to link it to the QTabWidget and according to this post it seems to be possible to do that but the problem is that when I compile nothing shows up as shows below:
Below is what I have done so far:
mainwindow.h
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
MainWindow(QWidget *parent = nullptr);
~MainWindow();
void onChangeTab(int index);
void newTab();
void closeTab(const int &index);
private slots:
void on_addTabBtn_clicked();
void on_tabWidget_tabCloseRequested(int index);
private:
Ui::MainWindow *ui;
QAction *addTab1;
QToolBar *mToolBar1;
QAction *addIconToolBar1;
};
mainwindow.cpp
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);
ui->tabWidget->clear();
ui->tabWidget->setTabsClosable(true);
ui->tabWidget->addTab(new QLabel("Add"), QString("Add"));
ui->toolBar->setContextMenuPolicy(Qt::ActionsContextMenu);
mToolBar1 = new QToolBar;
addIconToolBar1 = new QAction;
addIconToolBar1->setIcon(QIcon("qrc:/cardio.png"));
ui->toolBar->addWidget(mToolBar1);
ui->toolBar->addAction(addIconToolBar1);
connect(ui->addTabBtn, &QPushButton::clicked, this, [&] { ui->tabWidget->addTab(new QLabel("Add"), QString("Add")); });
connect(ui->tabWidget, SIGNAL(tabCloseRequested(int)), this, SLOT(closeTab(int)));
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::on_addTabBtn_clicked()
{
int index = 0;
if(index == this->ui->tabWidget->count() - 1) {
newTab();
}
}
void MainWindow::on_tabWidget_tabCloseRequested(int index)
{
ui->tabWidget->removeTab(index);
}
I tried to solve the problem in many ways and researched what the cause might be. I came across several references such as this one, which is the most important I found as the user seems to be doing it but there is no reference to documentation or no example to code to understand/study through.
Thanks for pointing to the right direction to solve this issue.
You can simply do something like this, and it really works.
QToolBar *toolbar=new QToolBar("toolbar",ui->tab);
toolbar->addAction("action1");
toolbar->addAction("action2");
enter image description here
I don't see where you are trying to add Toolbar to your TabWidget...
You must define Layout, add your toolbar to that layout and finally set layout to your tabWidget.
Try to do something like this, in your mainwindow constructor.
QHBoxLayout* tabWidgetLayout = new QHBoxLayout;
tabWidgetLayout->addWidget( your toolbar);
tabwidget->setLayout(tabWidgetLayout);
Also don't forget to include QHBoxLayout's header.
Even if other answers may seem to work, this is actually the right way to do what you asked for.
I have a QMainWindow opening a QDialog (not modal). When I minimize the main window, the dialog is closed as well. Can I somehow keep it open? (the other way round as in Keep QMainWindow minimized when QDialogs show() ).
One thing I have tried is to ignore the event, but to my surprise I never see such a state. Actually I only see ActivationChange (0n99) there.
void CMyDialog::changeEvent(QEvent *evt)
{
QEvent::Type t = evt->type();
if (t == QEvent::WindowStateChange)
{
evt->ignore();
hide();
}
else
{
QDialog::changeEvent(evt);
}
}
Question in Qt center dealing with a similar topic:
http://www.qtcentre.org/threads/24765-Intercept-minimize-window-event
Here I create it as member:
QScopedPointer<MyDialog> m_navigator{new MyDialog(this)}; // this here is the main application window
It is displayed by a public slot:
void MyDialog::toogleNavigator()
{
this->setVisible(!this->isVisible());
}
and is a QDialog derived class:
class MyDialog : public QDialog { ...
---- Edit 2 ------
First Wouter has mentioned it , then Alexander. It is like you guys say, if I pass no parent (as in Alexander`s minimal example), the dialog stays open - with parent it is minimized along with its parent. My apologizes Wouter.
However, in my case it does not work like that. So I did not turn Wouter`s comment without checking or in bad intention. Now it is my duty to find out why. I suspect some utility classes to alter the dialog. I will report back here when I have found the root cause.
Ok, it is the windows flags. If the dialog is a tool window, it is always minimized, as normal window it depends on the parent.
Try to create MyDialog without this(MainApplication) like parent
and may be play with a second parameter of the constructor.
new MyDialog(0/*, ?*/);
Addition It is working code
MainWindow.cpp
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
private slots:
void on_pushButton_clicked();
private:
Ui::MainWindow *ui;
QScopedPointer<Dialog> dialog;
};
MainWindow.hpp
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow),
dialog(new Dialog(0))
{
ui->setupUi(this);
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::on_pushButton_clicked()
{
dialog->setVisible(!dialog->isVisible());
}
I use QStackedWidget to handle multiple windows/forms in a Qt application
according to this question.
I use this pattern:
Add all widget objects to the QStackedWidget in mainwindow.cpp
Get signal from sub-window on request to change window
mainwindow replaces the window (it updates the QStackedWidget in the right slot)
My question :
is this the right way to do this? I have a lot of windows in my applications and want to ensure this is the common best practice.
This pattern means that i have pointers to all of the windows in my main window.
piece of my code:
mainwindow.cpp:
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
mnuWin = new Menu();
singlePulseWin = new SinglePulse();
repetitive = new Repetitive();
treatmentType = new TreatmentType();
//... and so on ....
connect(mnuWin,&Menu::updateMainWindowStackWidget,this,&MainWindow::onChangeWindowRequested);
connect(singlePulseWin,&SinglePulse::updateMainWindowStackWidget,this,&MainWindow::onChangeWindowRequested);
connect(repetitive,&Repetitive::updateMainWindowStackWidget,this,&MainWindow::onChangeWindowRequested);
connect(treatmentType,&TreatmentType::updateMainWindowStackWidget,this,&MainWindow::onChangeWindowRequested);
//... and so on ....
ui->pagesWidget->addWidget(mnuWin);
ui->pagesWidget->addWidget(singlePulseWin);
ui->pagesWidget->addWidget(repetitive);
ui->pagesWidget->addWidget(treatmentType);
//... and so on ....
ui->pagesWidget->setCurrentIndex(0);
}
void MainWindow::onChangeWindowRequested(int ind) //slot
{
ui->pagesWidget->setCurrentIndex(ind);
}
menu.cpp :
void Menu::on_btnMenuSinglePulse_clicked()
{
emit updateMainWindowStackWidget(1);
}
void Menu::on_btnMenuRepetitive_clicked()
{
emit updateMainWindowStackWidget(2);
}
void Menu::on_btnMenuBurst_clicked()
{
emit updateMainWindowStackWidget(3);
}
QStackedWidget is a good way to deal with Multi-window .why not put the buttons in the mainWindow ,so that you can change the pagesWidget's currentWidget more convenient instead of create signal-slot
Is there any standard way to create drop-down menu from QLineEdit without QCompleter? For example, using QMenu or creating own class. Or there are any other existing widgets?
Or maybe I should use QAbstractItemModel for QCompleter? I've thought about it, but I don't really understand this QAbstractItemModel. If you have experience about creating menu in this way, please also help me.
So I need a common type of drop-down menu: menu with lines, everyone of which includes icon (QPixmap) and text (QLabel) in itself. It's like in Opera or Chrome browser in address input line, like the right part of Apple Spotlight etc.
It's not possible with QMenu because it catch focus when showed and hides when loses focus. However, it's possible to use QListWidget (or any other regular widget) for this. I developed some working example for the proof of concept. It's default Qt Widget project with QMainWindow as main window. You need to add QLineEdit with name "lineEdit" into it and create slot for textChanged signa. Here's the code:
MainWindow.h:
class MainWindow : public QMainWindow {
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
private slots:
void on_lineEdit_textChanged(const QString &arg1);
private:
Ui::MainWindow *ui;
QListWidget* list;
};
MainWindow.cpp:
#include "MainWindow.h"
#include "ui_MainWindow.h"
#include <QDebug>
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow),
list(new QListWidget)
{
ui->setupUi(this);
list->setWindowFlags(Qt::WindowFlags(
Qt::FramelessWindowHint | Qt::WindowStaysOnTopHint));
list->setAttribute(Qt::WA_ShowWithoutActivating);
}
MainWindow::~MainWindow() {
delete list;
delete ui;
}
void MainWindow::on_lineEdit_textChanged(const QString &arg1) {
if (ui->lineEdit->text().isEmpty()) {
list->hide();
return;
}
list->clear();
list->addItem(ui->lineEdit->text());
list->addItem(tr("Google: ") + ui->lineEdit->text());
list->move(ui->lineEdit->mapToGlobal(QPoint(0, ui->lineEdit->height())));
if (!list->isVisible()) list->show();
}
There are several problems: you should hide menu when line edit loses focus or user move window, you can't set focus on the menu using down arrow button from line edit, etc. But I believe all these issues can be solved easily.
From what you describe, you could try an editable QComboBox: It has its own model and view, its own completer, and can display icons.
QComboBox *comboBox = new QComboBox;
...
comboBox->setEditable(true);
// The completer popup isn't enabled by default
comboBox->completer()->setCompletionMode(QCompleter::PopupCompletion);
And since that QCompleter can display icons, I guess you can use a regular QLineEdit with a QCompleter and a model with icons. For the model, you can use a QStandardItemModel.
A am trying to make a program that takes a signal from one class and with activation of that signal I want to activate a slot in second class.
In my case the first class is the mainWindow class, this class is subClass of QMainWindow, and in this class is the slot that I want to activate.
This is mainWindow.cpp:
mainWindow::mainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::mainWindow)
{
ui->setupUi(this);
}
mainWindow::~mainWindow()
{
delete ui;
}
void mainWindow::slotForStatusBarMessage(QString string)
{
statusBar()->showMessage(string);
}
The second class is the mainWidget class and it is a subclass of QWidget.
This is mainWidget.cpp:
mainWidget::mainWidget(QWidget *parent) :
QWidget(parent)
{
buttonAddNewRecord=new QPushButton("Add new record", this);
layoutButton=new QHBoxLayout();
layoutButton->addWidget(buttonAddNewRecord);
layoutMain=new QVBoxLayout();
layoutMain->addLayout(layoutButton);
functionDatabaseOpen();
setLayout(layoutMain);
}
The signal is emited from functionDatabaseOpen() function:
if (sqlDatabase.open())
{
emit signalForShowMessageInStatusBar("true");
}
else
{
emit signalForShowMessageInStatusBar("false");
}
I have made all the settings to the database but i didnt copy here because of space.
I have tried to make connection inside main.cpp but it seems it dosent work.
QObject::connect(mw, SIGNAL(signalForShowMessageInStatusBar(QString)), w, SLOT(slotForStatusBarMessage(QString)));
I cant make this signal/slot connection between classes to work. Can you give me any help.
If you have any question about the code please ask. Sorry for the bad english,I am not a native english speaker.
Thank you very much for your help.
You are emitting the signal from the constructor of mainWidget, and since the connection is only done after you return from that constructor, the signal doesn't go anywhere.
The easiest fix, not knowing what the rest of the code looks like, would be to move the call to functionDatabaseOpen() in main() after the signal/slot connection is made.