connect from a QTab (in a QTabWidget) back to QMainWindow - qt

The main Part of my Application is a Systray-Menu. For maintenance there should be a normal GUI.
My Problem is that now I have to create two Signal/Slot-Connections back to the MainWindow from each Tab. This is for minimizing the GUI and to update the Menu. I don't know how to do this.
I tried to connect with this->parent->parent from the ManageSession and ui_manag->session_ui->minimizeButton from MainWindow. I have a little knot in my head and am asking for help. Or should I re-think my design? I´m using only QtCreator 2.6.1 with Qt 4.8.4.
Screenshots of the GUI-Elements
This is the mainwindows.cpp:
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
{
setWindowTitle(QCoreApplication::applicationName());
QWidget *mainWidget = new QWidget;
QTabWidget *ui_manag = new ManageTab;
QVBoxLayout *mainLayout = new QVBoxLayout;
mainLayout->addWidget(ui_manag);
mainWidget->setLayout(mainLayout);
setCentralWidget(ui_manag);
ui_manag->setCurrentIndex(0);
//Here comming Code to setup a TrayIcon, the Database and the Menus
}
The Tab is completely generated by the Designer:
ManageTab::ManageTab(QWidget *parent) :
QTabWidget(parent),
tab_ui(new Ui::ManageTab)
{
tab_ui->setupUi(this);
}
For each Setting I use the same GUI with multiple inheritance:
ManageSession::ManageSession(QWidget *parent) :
QWidget(parent),
session_ui(new Ui::ManageWidget)
{
session_ui->setupUi(this);
session_ui->manageLabel->setText(tr("Manage Session"));
connect(session_ui->addButton, SIGNAL(clicked()), this, SLOT(addButton_clicked()));
connect(session_ui->editButton, SIGNAL(clicked()), this, SLOT(editButton_clicked()));
connect(session_ui->deleteButton, SIGNAL(clicked()), this, SLOT(deleteButton_clicked()));
}
//Here follows the Functions for manipulating the TableView
// and emmiting a Signal to Update the Menu

Let's remake it in an answer (so you can accept it, hehe. j/k, to long for a comment):
First. As i said in comment:
You are inheriting without specifying access. So it defaults to private. That's why
ui_manag->session_ui->minimizeButton
wont allow you to access the button.
Second.
parent is a method, so It's: this->parent()->parent() or just parent()->parent() ;)
Again, it probably needs to inherit public. Not sure, tho.
That should work then.

Related

How to connect a signal in Qdialog to a slot in QMainwindow

I work with QT Creator 4.9.1 and i've made a gui with the designer. I have a MainWindow with a stackedWidget and round about 60 pages, inside my mainwindow i have a button, with the onButton_clicked signal i open a dialog(show picture) to insert a number to set the page the user want to see inside the mainwindow.
My Problem is that the SIGNAL comes from the Dialog with the name on_pushButton_Enter_clicked and my SLOT is inside my mainwindow with the name setCurrentIndex(). I,ve read the post's: "How to Connect Signal from MainWindow to Slot in Dialog" and "Qt connect mainwindow and dialog using signal and slot".
But that doesn't help me because my dialog doesn't know about my mainwindow and i don't know how i can connect them.
Signal:
Dialognummer_eingeben.h
...
signals:
void enterButtonPressed();
...
void Dialognummer_eingeben::on_pushButton_Enter_clicked()
{
QString text = ui->lineEdit_Dialognummer->text();
ui->lineEdit_Dialognummer->setText("");
this->reject();
emit enterButtonPressed();
}
Slot:
Terminal::Terminal(QWidget *parent) : QMainWindow(parent), ui(new Ui::Terminal)
{
ui->setupUi(this);
QObject::connect(&dialog, SIGNAL(enterButtonPressed()), this, SLOT(setCurrentIndex()));
}
void Terminal::setCurrentIndex()
{
int num = dianr.getNum();
QString strNum = QString::number(num);
switch(num)
{
....
}
}
Edit: 1. Add signal and slot code
2. Make some changes inside the code
inside my mainwindow i have a button, with the onButton_clicked signal i open a dialog(show picture) to insert a number to set the page the user want to see inside the mainwindow.
You have to additionally add a signal in your dialog class which should be emitted once enter button was pressed, using on_pushButton_Enter_clicked as a function is not enough. Add a signal in the dialog class, like "enterButtonPressed()" and emit it in the function on_pushButton_Enter_clicked.
Inside the mainwindow (at some point where the dialog is created) add this line:
connect(dialog, SIGNAL(enterButtonPressed()), this, SLOT(SlotNameWhichShouldGetCalled()));
EDIT: Even if the above solution should work, a better solution came to my mind.
You generally should use the QDialog::accepted signal to connect to (see https://doc.qt.io/archives/qt-4.8/qdialog.html#accept).
Concrete steps:
In on_pushButton_Enter_clicked() at the bottom of the code add accept() instead of this-reject() (I assume you want the dialog to be closed succesful and not as rejected?)
Connect to the QDialog::accepted() signal by adding
QObject::connect(&dialog, SIGNAL(accepted()), this, SLOT(setCurrentIndex()));
Additionally ensure that you have no error in the connect(...) function. If the signal/slot is not found or is not matching you should see something in your application output in Qt Creator

Proper way to manually set the layout of a window in Qt

I need a QMainWindow layout to change depending on the number of cores.
Therefore I set it manually (not using the Design mode).
My question is:
After this layout was created, how can I refer to the widgets it contains?
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
//...
buildLayout();
//...
// Now I'd like to use something like this:
// ui->threadingTable->...
// However, it's not the member of ui
}
void MainWindow::buildLayout()
{
QWidget *window = new QWidget(this);
QTableView *threadingTable = new QTableView(window);
//...
QGridLayout *layout = new QGridLayout(window);
layout->addWidget(threadingTable, 0, 0);
//...
window->setLayout(layout);
this->setCentralWidget(window);
}
I can get the QLayoutItem out of this->centralWidget().
Or I can make all widgets in layout members of MainWindow class and access them directly.
However, I feel that neither of these is the right way.
Is there a way to pass the widgets to ui?
So that I could access them by calling
ui->threadingTable
Both options are fine. It is possible to get pointer to threadingTable from the main class member or directly from the objects hierarchy:
qDebug() << qobject_cast<QGridLayout *>(this->centralWidget()->layout())->itemAtPosition(0, 0)->widget();
qDebug() << this->centralWidget()->layout()->itemAt(0)->widget();
Of course, null verification may be required. You can also check this question QGridLayout: Getting the list of QWidget added.
The class Ui::MainWindow is automatically generated from the .ui xml form that can be generated in the Design mode: "Using a Designer UI File in Your Application"
Since the layout is constructed manually the .ui file and the ui instance is not needed at all. You can remove them from your project.
On the other hand, it is possible to use custom widgets even in the Design mode in .ui forms.
So, if you need some tricky object you can build the entire form in handy Design mode and then, for example, the standard QTableView may be promoted to your CustomTableView that is inherited from QTableView. That custom class may implement some special behavior.

Enabling a QPushButton when an item is selected in a QListView

I basically got a QPushButton and a QListView connected to a QStandardItemModel.
The QPushButton allows to delete the selected items in the QListView. I'm trying to get the QPushButton only enabled if at least one item is selected in the QListView, but I can't find the correct signal for that.
The right signal is QItemSelectionModel::selectionChanged. QItemSelectionModel object can be obtained using view->selectionModel().
clicked(QModleIndex) looks like it can be a decent starting point - if you setup a slot to receive that notification, you should be able to enable your button.
Using QtCreator/Designer:
void MainWindow::on_listWidget_clicked(const QModelIndex &index)
{
ui->pushButton->setEnabled(true);
}
Without QtCreator, the connection would break down into something like this (Qt4 style):
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent)
{
QListWidget* listWidget = new QListWidget();
// ... setup ui stuff, etc ...
connect(listWidget, SIGNAL(clicked(QModelIndex)),
this, SLOT(on_listWidget_clicked(QModelIndex));
}

How can I add another tab that looks exactly like the first one (like in a browser)?

I have a browser made in Qt and a I have a tabwidget with one tab (which has a label, lineedit and a webview). I want to add others that look like the first one (have label, lineedit and webview).
How can I do this?
I don't know of any way to "clone" or duplicate an existing tab or widget, so I believe you'll need to code the tab contents yourself (i.e. not through the designer).
If all you need are a QLabel, a QLineEdit and a QWebView, that's not very complex. The idea would be to:
create a custom widget (inheriting from QWidget directly, or from QFrame)
lay out the contained widgets in the fashion you want in its constructor
add as many tabs as you want, when you want them, via the QTabWidget.addTab function.
The Tab Dialog example has everything you need - it's actually more complex than what you need because it uses different widgets for each tab. You can get away with a single widget.
If you wonder how to do the layout, and you're satisfied with what you got from the designer, you can inspect the generated (.moc) files. You'll see what layouts it uses, and you can replicate that in your own code.
Skeleton widget:
class BrowserTab : public QWidet
{
Q_OBJECT
public:
BrowserTab(QUrl const& home, QWidget *parent = 0);
void setUrl(QUrl const& url);
private:
QWebView *web;
QLabel *title;
QLineEdit *urlEdit;
};
BrowserTab::BrowserTab(QUrl const& home, QWidget *parent)
: QWidget(parent)
{
urlEdit = new QLineEdit(this);
title = new QLabel(this);
web = new QWebView(this);
QVBoxLayout *vl = new QVBoxLayout;
vl->addLayout(title);
vl->addLayout(urlEdit);
vl->addLayout(web);
setLayout(vl);
setUrl(home);
}
void BrowserTab::setUrl(QUrl const& url)
{
web->load(url);
// update label & urlEdit here
}
You'll need to do a bit more to make it a proper browser (setUrl should probably be a slot too), but this should get you started.

Creating a Symbian's like application menu at S60

I wanted to make an app which is when started it shows a menu. It is just like when you open a Messaging app in S60. Here is a screenshot.
How do I make it? I have tried to make the centralWidget of the QMainWindow as QMenu, and adding QAction to the QMenu. But when I'm running it, the app don't show anything. And I have tried to make the QMenu using QMenuBar. And it is show okay. But I can't use the up/down key to select menu in the device. And when I press the options key (Qt::PositiveSoftKey), the menubar shows up too. And I didn't even add that to menuBar() which is owned by QMainWindow.
Here is my first code:
QAction* act1= new QAction(tr("act1"),this);
QObject::connect(tes,SIGNAL(triggered()),this,SLOT(close()));
QAction* act2= new QAction(tr("act2"),this);
QObject::connect(tes,SIGNAL(triggered()),this,SLOT(close()));
QMenu* menu = new QMenu(this);
menu->addAction(act1);
menu->addAction(act2);
setCentralWidget(menu);
And it shows nothing at the apps.
And here is my second try:
Qt Code: Switch view
QAction* act1= new QAction(tr("act1"),this);
QObject::connect(tes,SIGNAL(triggered()),this,SLOT(close()));
QAction* act2= new QAction(tr("act2"),this);
QObject::connect(tes,SIGNAL(triggered()),this,SLOT(close()));
QMenuBar* menubar = new QMenuBar(this);
QMenu* menu = menubar->addMenu(tr("menu"));
menu->addAction(act1);
menu->addAction(act2);
setCentralWidget(menu);
It shows the menu. But when I deploy to the device, I can't use the keypad to select the menu. And at the simulator, if I click other place than the QAction item, the menu lost.
I am using another approach by using QPushButton with Vertical Layout. Here is the code:
QWidget* centralWidget = new QWidget(this);
QScrollArea* scrollArea = new QScrollArea(this);
scrollArea->setWidget(centralWidget);
scrollArea->setWidgetResizable(true);
setCentralWidget(scrollArea);
QVBoxLayout* centralLayout = new QVBoxLayout(centralWidget);
QPushButton* button1 = new QPushButton(tr("button 1"));
QPushButton* button2 = new QPushButton(tr("button 2"));
centralLayout->addWidget(button1);
centralLayout->addWidget(button2);
centralLayout->setContentsMargins(0,0,0,0);
button1->setFocus();
Here it's look:
Okay, and that's look good enough. But if that's have 8 button. If it is only have 2 button, it looks like this:
looks kind of weird, huh? Any way to prevent this?
For me, the UI that you're trying to replicate is a list of options, so, why don't try to create the UI based on a list widget?
Asumming that you're going to use a list, you have to options from which you have to choose based on your needs and your app requirements:
Qt Widgets: Available in all the Qt supported Plataforms. Created for desktop and works great on it, but in feel strange on mobile devices. Take a look to the QListWidget and QListView.
Qt Quick: It isn't available for S40 phones or S60 3rd edition, not available for non-touch phones, basically. Created for "touch enabled UI's", it doesn't offer a stable set of widgets (buttons, comboboxes) yet, but it offers a set of primitives (like rectangles or images) that gives you a lot of freedom to create your UI's and it looks pretty good. I think that this is what Lucian used to create the UI from his answer.
This examples could be of particular interest: http://doc.qt.io/archives/qt-4.7/all-examples.html
Run the QtDemo to see all the examples live!
Hope it helps!
EDIT: Adding example of QListWidget
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent), ui(new Ui::MainWindow)
{
ui->setupUi(this);
for(int i=0; i<10; i++) {
QListWidgetItem *item = new QListWidgetItem(QIcon("Qt.png"), QString("Item %1").arg(i));
ui->listWidget->insertItem(i, item);
}
ui->listWidget->setIconSize(QSize(64, 64));
connect(ui->listWidget, SIGNAL(itemClicked(QListWidgetItem*)), this, SLOT(onItemClicked(QListWidgetItem*)));
}
void MainWindow::onItemClicked(QListWidgetItem *item)
{
QMessageBox::information(this, "", QString("%1 pressed").arg(item->text()));
}
You have all the freedom in the world to create your layout the way you like. Want those buttons closer together? Want them centered in the view?
The attached image took me 30 seconds to create and looks already decent (according to my pour designer skills).

Resources