I want to add tabs dynamically in a Qt application depending on user inputs.
One tab is to be there all the time by default. For convenience, it would be great if I could create the layout and features of this tab in the graphic editor. Then I would like to transfer this layout into code, put in a class constructor and add tabs like:
ui->tabWidget->addTab(new myTabClass(), "Tab 2");
I want to promote this tab programatically as well. Is that possible?
For adding tabs dynamically and constructed by a class, you can use an additional .ui file. This way you can do all the layout stuff with the Qt Designer GUI.
1) Create an empty tab widget in the mainwindow.ui. (eg. named myTabWidget)
2) Add to your project directory a new “Qt Design Form Class” as QWidget class, not as QTabWidget (eg. named MyTabPage):
Right click project -> Add new -> Qt -> Qt Design Form Class
3) In the mytabpage.ui you make the design as you want it to be inserted in myTabWidget.
4) The next step you can instantiate MyTabPage in the MainWindow constructer or elsewhere and add it to myTabWidget. The empty tab in myTabWidget can be removed before. To access paramaters form myNewTab you need a function declared in MyTabPage.
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
MyTabPage *myNewTab = new MyTabPage;
ui-> myTabWidget ->removeTab(0);
ui-> myTabWidget ->addTab(myNewTab, tr("name"))
myNewTab->functionDeclaredInMyTabPage (); //access parameters of myNewTab
}
PS: I am aware the question is old. But I want to offer a step by step solution to others cause I had to struggle with it for my self recently.
You can insert tab by int QTabWidget::insertTab ( int index, QWidget * page, const QIcon & icon, const QString & label ) which inserts a tab with the given label, page, and icon into the tab widget at the specified index :
ui->tabWidget->insertTab(1,new myTabClass(),QIcon(QString(":/SomeIcon.ico")),"TabText");
Also removing a tab is done by QTabWidget::removeTab ( int index ).
Related
I'm looking to generate a set of labels and buttons based on some kind of template, but I don't know how to do the template part.
I'll be using a tab widget which I already have set up, and in one the tabs, I want to have a two labels, a custom button, and a textbox. It'll be repeated around 40-50 times (dependent on a given value at startup) and have spacing as needed.
Once I have a template, I foresee calling it in a loop and setting the appropriate displayed text(Label_1, Label_2, etc) and connect statements where needed.
As I said, I don't know how to template parts of the UI so they can be placed in a kind of auto-generation.
I had thought of making one group, copying the xml, and somehow adding it but that doesn't seem to be a proper way. A little new to Qt.
This is roughly the layout I want to repeat. It has two labels, a lineedit, and one pushbutton.
There's no "good" way to do this in QtDesigner/QtCreator. At best you could copy/paste the set of controls 50 times and then in C++ code hide the ones you don't need. But I wouldn't recommend this.
Instead, just create the controls (labels/button/text box), and a layout to hold them, in C++ code, inside a loop which iterates however many times you need at runtime. Insert the controls layout into the tab widget page layout which you have set up in designer mode. It is not difficult, and will actually be more efficient than what QtDesigner produces since that tends to generate more code than you typically need in the first place.
As a starting point, you could look at the C++ code which is generated by the Qt UI Compiler (UIC) tool for your current design (it takes the XML from designer and turns it into C++ code). You can find this in the build folder for your project, typically named something like ui_ClassName.h, probably in a ui subfolder of the build tree.
UPDATE:
Another, possibly better, way to do this is to create the "template" QWidget class/form, which is going to be used multiple times, as a separate object. The "template" design could be created/maintained using QtCreator/Designer (or just directly in C++). The (possible) advantage here is that as the app requirements evolve, the template widget can be expanded with additional functionality or even re-used in other parts of the UI.
For example, I'd assume the text editor and button in the given mockup image will actually need to do something (eg. edit data and submit it). So some basic functionality can be built into the "template" widget, for example to emit a signal with the text contents of the line editor when the button is pressed.
I put together a quick example. I'm creating the simple MainWindow in pure C++ to simplify/shorten the example code. The "template" I'm calling an Editor. The Editor class and UI form I initially created with the QtCreator wizard (New -> Qt Designer Form Class). I then added the label/control widgets in designer mode. And in C++, a textEdited(const QString &text) signal in the header, and in the Editor() constructor a lambda connection to emit that signal when the button is pressed.
The Editor class code is straight out of the QtCreator wizard except for two edits I'm highlighting below. The designer form has two relevant controls: a QLineEdit (lineEdit) and a QPushButton (pushButton). I'll link to the full files below.
Editor.h
// in the Editor class declarations:
signals:
void textEdited(const QString &text) const;
Editor.cpp
// in the constructor, after ui->setupUi(this);
connect(ui->pushButton, &QPushButton::clicked, this, [this]() {
emit textEdited(ui->lineEdit->text());
});
Test harness, including MainWindow subclass and main()
#include <QApplication>
#include <QMainWindow>
#include <QTabWidget>
#include <QBoxLayout>
#include <QMessageBox>
#include "Editor.h"
class MainWindow : public QMainWindow {
Q_OBJECT
public:
MainWindow() : QMainWindow()
{
// set up a tab widget as the window central widget
QTabWidget *tabWidget = new QTabWidget(this);
setCentralWidget(tabWidget);
// the first/only page will contain all the editors in a vertical layout
QWidget *editorsPage = new QWidget(this);
editorsPage->setLayout(new QVBoxLayout());
// add the editors container page to tab widget
tabWidget->addTab(editorsPage, tr("Editors page"));
// Now create a number of editor widgets using our Editor class "template"
int layoutItems = 5; // number of editors needed, could be dynamic
for (int i=0; i < layoutItems; ++i) {
// Create an Editor instance with the tab page as parent
Editor *editor = new Editor(editorsPage);
// Add the editor widget to the tab page layout
editorsPage->layout()->addWidget(editor);
// A simple connection with the editor signal, as way of example.
connect(editor, &Editor::textEdited, this, [this](const QString &text) {
// just show a message box with the editor text
QMessageBox::information(this, tr("Text Edited"), text, QMessageBox::Ok);
});
}
}
};
int main(int argc, char **argv)
{
QApplication app(argc, argv);
MainWindow mainWindow;
mainWindow.show();
return app.exec();
}
#include "main.moc"
Links The full Editor code:
Editor.h
Editor.cpp
Editor.ui
The XML in Qt Creator is for UIC in QMake to generator code for you.
For example, QMake translates your mainwindow.ui to ui_mainwindow.h, and within you will find void setupUi(QMainWindow *MainWindow) with the actual code that creates and places the widgets.
Look at this code, the docs, and create and place the widgets yourself by code.
For example, adding 5 checkboxes to a groupbox by code:
QVBoxLayout *l = new QVBoxLayout(this);
ui->groupBox_4->setLayout(l);
for(int i=0; i<5; i++){
QCheckBox *c = new QCheckBox(this);
l->addWidget(c);
}
I try to make a table view (using table widget in qt designer)
Now i make a columns but i want to make "columns in column" let see a screen:
http://i.imgur.com/OUABoWt.jpg
Btw. It is possible that QT designer can update code from class?
i.e
test::test(QWidget *parent)
: QMainWindow(parent)
{
ui.setupUi(this);
ui.tableWidget->setColumnWidth(0, 20);
}
If i compile program ofc i have first column width = 20 px but in qt designer i have default size.
Qt does not have the concept of sub-column. You should implement it in your own which can be done by using an item delegate for the specific column.
You can also have a look Qt Grid View and download the source code to get a hint about the implementation.
For example I have 20 widgets on a form. I need to resize them based on screen resolution so here's my method
newHeight=(desktopHeight * ui->widget1->height())/768;
newWidth=(desktopWidth * ui->widget1->width())/1024;
newY=(desktopHeight * ui->widget1->y())/768;
newX=(desktopWidth * ui->widget1->x())/1024;
ui->widget1->setGeometry(newX,
newY,
newWidth,
newHeight);
newFontSize=(desktopHeight * ui->widget1->font().pointSize())/768;
ui->widget1->setFont(QFont ("Ubuntu",newFontSize, QFont::Bold));
And I will repeat this method for the remaining 19 widgets. Is there a way to get all of the widgets and create a do while statement and create a function that the widgets are the parameter?
Are all the widgets attached to a form or window?
You can just grab all the child widgets from their UI parent widget and iterate over the collection of children.
Depending on your widget hierarchy you should just do something like
QObjectList *widgetList = parentWidget->findChildren();
In your specific case:
QObjectList *widgetList = ui->centralWidget->findChildren();
Edit: Without the rest of your code I have no idea what ui represents, hence my generic answers. I was assuming your ui was a MainWindow as follows in my code
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
QObjectList widgetList = ui->centralWidget->children();
qDebug() << "Amount of children found :" << widgetList.count();
}
reggie! Don't you think that you are doing it wrong?
About layouts
Your approach is used for very specific cases, because there are ready-to-use from the box solution in Qt, called Layout management.
Here you can read about it: Layout Management, also, see example of usage and intuitive how-to use it in Qt designer
About fonts:
There is QApplication::setFont, so you can change font program-wide.
But in official documentation you can find:
This function lets you override the default font; but overriding may be a bad idea because, for example, some locales need extra large fonts to support their special characters.
This is my UI:
This is tab created programmatically:
ui->tabWidget->addTab(new QWidget(), "Tab 2");
I want the newly created tab to have the exact same layout as the "Chat room" tab has. Any advice on how to do this would be great.
The easiest way to do this (in Designer) is to create a new UI Form Class called something like ChatTab and base it on QWidget.
Move (i.e., cut and paste) your chat room widgets and layout from your MainWindow UI form to the ChatTab form, but leave the QTabWidget container in your MainWindow form. If you want a chat room to be in your main window when it first opens, promote its first QWidget to a ChatTab from inside Designer.
Any additional tabs should be added programatically like so:
ui->tabWidget->addTab(new ChatTab(), "Tab 2");
Add fancy stuff to the ChatTab constructor if you want to make your life easier.
You should create a custom QTabWidget for this layout, as name ChatWidget, and make a factory API like this:
ChatWidget * ChatWidget::creater(TabWidget * tw, ChatData * cd) {
ChatWidget * cw = ChatWidget.create();
tw.addTab(cast<QWidget>cw, 0);
// some init
...
return cw;
}
Long time not use Qt and C++, may be this give you a hint.
Use your current chatRoom class as a base class and do some layout stuff in it;
Next time you want to create a new tab, just do something like:
ui->tabWidget->addTab(new chatRoom(), "Tab 3");
Hope to help.
MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWindow)
{
this->setupUi(this);
this->setupActions();
this->setWindowTitle(tr("CuteEdit"));
label = new QLabel(tr("No Open Files"));
this->setCentralWidget(label);
label->setAlignment(Qt::AlignCenter);
}
By above code, I get a GUI like this(Its a screenshot of whole screen, Only observe the window displayed in middle of page of ebook). (I used QT Designer)
Now, i want user to select File->Open.. A Dialog appears and file gets selected.. Its contents are to be displayed in *textEdit widget..
Function for that is below..
void MainWindow::loadFile()
{
QString filename = QFileDialog::getOpenFileName(this);
QFile file(filename);
if (file.open(QIODevice::ReadOnly|QIODevice::Text))
{
label->hide();
textEdit->setPlainText(file.readAll());
mFilePath = filename;
QMainWindow::statusBar()->showMessage(tr("File successfully loaded."), 3000);
}
}
The window crashes at line:-
textEdit->setPlainText(file.readAll());
But if i comment the line:-
this->setCentralWidget(label);
i mean i remove label as being the central widget, the program runs as expected.. Why?
And also, I am not clear about the concept of CentralWidget. Pls guide.
JimDaniel is right in his last edit. Take a look at the source code of setCentralWidget():
void QMainWindow::setCentralWidget(QWidget *widget)
{
Q_D(QMainWindow);
if (d->layout->centralWidget() && d->layout->centralWidget() != widget) {
d->layout->centralWidget()->hide();
d->layout->centralWidget()->deleteLater();
}
d->layout->setCentralWidget(widget);
}
Do you see that if your MainWindow already had centralWidget() Qt schedules this object for deletion by deleteLater()?
And centralWidget() is the root widget for all layouts and other widgets in QMainWindow. Not the widget which is centered on window. So each QMainWindow produced by master in Qt Creator already has this root widget. (Take a look at your ui_mainwindow.h as JimDaniel proposed and you will see).
And you schedule this root widget for deletion in your window constructor! Nonsense! =)
I think for you it's a good idea to start new year by reading some book on Qt. =)
Happy New Year!
Are you sure it's not label->hide() that's crashing the app? Perhaps Qt doesn't like you hiding the central widget. I use Qt but I don't mess with QMainWindow that often.
EDIT: I compiled your code. I can help you a bit. Not sure what the ultimate reason is as I don't use the form generator, but you probably shouldn't be resetting the central widget to your label, as it's also set by the designer, if you open the ui_mainwindow.h file and look in setupGui() you can see that it has a widget called centralWidget that's already set. Since you have used the designer for your GUI, I would use it all the way and put the label widget in there as well. That will likely fix your problems. Maybe someone else can be of more help...
I'm not sure I understood your problem, neither what the guys above said (which I guess are valid information) and it seems to be an old topic.
However, I think I had a problem that looks like this and solved it, so I want to contribute my solution in case it helps anyone.
I was trying to "reset" central widget using QLabels. I had three different ones, switch from first to second, then to third and failed to switch back to the first one.
This is my solution that worked:
Header file
QLabel *imageLabel;
Constructor
imageLabel = new QLabel("<img src='/folder/etc.jpg' />");
this->setCentralWidget(imageLabel);
Reset
imageLabel = NULL;
imageLabel = new QLabel("<img src='/folder/etc.jpg' />");
this->setCentralWidget(imageLabel);
Hope that helps
Aris