SIGSEGV when adding widget in Qt - qt

I implemented example (chapter 2) from "Mastering Qt 5" book but the code crashes when adding widget to centralWidget's layout:
ui->centralWidget->layout()->addWidget(&mCpuWidget)
I suspect that the centralWidget does not have layout, hence it crashes but I don't know how to fix that?
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow),
mCpuWidget(this)
{
ui->setupUi(this);
SysInfo::instance().init();
ui->centralWidget->layout()->addWidget(&mCpuWidget);
}
Here are two more classes which might help figure out the problem. Some of you might have the book too with all of the code (hence I mentioned it).
CpuWidget::CpuWidget(QWidget* parent):
SysInfoWidget(parent),
mSeries (new QPieSeries (this))
{
mSeries->setHoleSize(0.35);
mSeries->append("CPU Load", 30.0);
mSeries->append("CPU Free", 70.0);
QChart* chart = chartView().chart();
chart->addSeries(mSeries);
chart->setTitle("CPU Average Load");
}
This class creates and sets layout (QVBoxLayout)
SysInfoWidget::SysInfoWidget(QWidget *parent, int startDelayMs, int updateSeriesDelayMs) :
QWidget(parent),
mChartView(this)
{
mRefreshTimer.setInterval(updateSeriesDelayMs);
connect(&mRefreshTimer, &QTimer::timeout,
this, &SysInfoWidget::updateSeries);
QTimer::singleShot(startDelayMs,
[this] {mRefreshTimer.start();});
mChartView.setRenderHint(QPainter::Antialiasing);
mChartView.chart()->legend()->setVisible(false);
QVBoxLayout* layout = new QVBoxLayout(this);
layout->addWidget(&mChartView);
setLayout(layout);
}

I'm the co-author of the book "Mastering Qt 5" !
I guess your suspicion about the layout is correct:
ui->centralWidget->layout()->addWidget(&mCpuWidget);
Without any layout defined the returned item is null so you can't call the method layout().
If you have some errors during your learning you should refer to the final source code hosted on github here: https://github.com/PacktPublishing/Mastering-Qt-5
Take a look to the the file "Mastering-Qt-5/Chapter_02/MainWindow.ui":
<ui version="4.0">
...
<widget class="QWidget" name="centralWidget">
<layout class="QHBoxLayout" name="horizontalLayout"/>
</widget>
...
</ui>
As you can see for this project, a horizontalLayout of type QHBoxLayout is defined in the centralWidget. You can easily edit a ".ui" file with a text editor from Qt Creator with the following steps:
Right-click on "MainWindow.ui" in the Project hierarchy view
Select "Open-With"
Finally "Plain text editor"
Select "Form editor" when you want to come back to the WYSIWYG editor.
As suggested in other answers, the way to do it from C++ with the following line is also correct:
ui->centralWidget->setLayout(new QHBoxLayout());
Thank you for highlighting the lack of information about the layout here. I created an issue to add an errata about this topic.

Unless I have missed something in the code you have provided you haven't actually set your central widget. By default calling QMainWindow::centralWidget() returns a NULL pointer. You need to first call QMainWindow::setCentralWidget(QWidget* yourCentralWidget) before you call it. And yes, you also need to add a layout to it if you want to use layout()->addWidget(...). You can create an instance of a generic QWidget, set its layout, set is a central widget and then work with it.

You can fix your problem either by adding a layout in C++:
ui->setupUi(this);
SysInfo::instance().init();
ui->centralWidget->setLayout(new QVBoxLayout()); // Or any other layout class
ui->centralWidget->layout()->addWidget(&mCpuWidget);
Or in the UI Designer by using those buttons:
Note that for the buttons to be active you need to have at least 1 widget in your central widget and then select your central widget. You can then write:
ui->setupUi(this);
SysInfo::instance().init();
// One way
ui->centralWidget->layout()->addWidget(&mCpuWidget);
// Another way
ui->layout->addWidget(&mCpuWidget);
Finally you could also move your CpuWidget to the ui file using the "Promote to..." option in the contextual menu. In this case you would not need mCpuWidget but you could access it using something like ui->cpuWidget.
For more info read the Qt Designer manual:
Using Layouts in Qt Designer
Using Custom Widgets with Qt Designer

Related

How to make QtDesigner offer Enumeration for Plugin Property

I'm trying to deploy my Qt Ui Widget as a Qt Designer Plugin in accordance to the Guide at https://doc.qt.io/qt-5/designer-creating-custom-widgets.html
However, I just can't seem to figure out how to make QtDesigner present the User with a Dropdown in the Property-Editor for Enumeration Properties.
Any suggestions are greatly appreciated!
Answering my own question:
1) put the enum right after the "public:" of your class and immediately thereafter use the Q_ENUM macro
class myEnumContainingClass {
Q_OBJECT
Q_PROPERTY(FOO my_property READ getMyEnumProperty WRITE setMyEnumProperty DESIGNABLE true)
public:
enum FOO {
BAR
};
Q_ENUM(FOO)
explicit MyEnumContainingClass();
...
2) use only the key of the enum, not the whole enum::string in the domXml()-section of the plugin like this
<property name="theEnumHoldingProperty">
<enum>BAR</enum>
</property>
Although I would have still preferred to have the whole enum::string appear in the Dropdown within Qt Designer for consistency, at least it works this way.

QTabWidget methods not available in QtDesigner

One of the methods available in the QTabWidget class is setTabEnabled - I can't see of a way to set this in QtDesigner (I know I can set it in the code) - is there a specific reason why this method (and presumably others?) aren't settable in QtDesigner?
Just change enabled property of respective widget inside QTabWidget.
according to documentation this suppose to work. I've taken a look on QTabWidget code and it looks like either documentation is wrong or there is a bug in code. I will not explain why just provide workaround on it.
Create this method:
void tabBarWorkaround(QTabWidget *tabWidget) {
for (int i=0; i<tabWidget->count(); ++i) {
tabWidget->setTabEnabled(i, tabWidget->widget(i)->isEnabled());
}
}
And use it in construction time:
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
tabBarWorkaround(ui->tabWidget);
}
From this moment changing enabled property of page in designer will work like you want.
I've test this with Qt 5.2.1 and it works.
I've realised that there are two separate possible events:
unchecking the 'enabled' checkbox for a tab widget in QtDesigner actually invokes self.<tabname>.setEnabled(False), which seems to disable all child widgets within the tab, but does not disable the tab button itself(!)
Disabling the tab button so that it's not clickable is not possible in QtDesigner, but is possible in code (as discussed in the previous answer): self._uiform.<tab frame>.setTabEnabled(<tab index>,False)

qt layout()->setSizeConstraint

I have a problem with the layout () in Qt 5.
I want to make a dynamic variable dialog.
![enter image description here][1]
Below is the code for the constructor:
SortDialog :: SortDialog (QWidget * parent)
     : QDialog (parent)
{
     setupUi (this);
     SecondaryGroupBox-> hide ();
     TertiaryGroupBox-> hide ();
     layout () -> setSizeConstraint (QLayout :: SetFixedSize);
     setColumnRange ('A', 'Z');
}
The project is built successfully, but when you start receiving a signal from the operating system.
Signal: SIGSEGV
Purpose: Segmentation fault
If you delete a row
layout () -> setSizeConstraint (QLayout :: SetFixedSize);
The program works.
Please, help me.
P.s.:This is an example from the book c++ GUI Programmming with Qt 4 (page 31)
I was having the same problem.
I just solved it.
Probably you don't want the answer after two years, but I really want to write about this somewhere, because there is nothing about this little issue on the web.
The problem was that Qt Designer didn't generate code to set dialog's layout.
I just opened ui_sortdialog.h and found that out of SortDialog a widget was created. Than with this widget a layout would be created. The layout is called gridLayout_4, and every widget and layout of the form are added to this one. When I added to function retranslateUi line SortDialog->setLayout(gridLayout_4); everything worked. Generated code created layout and did everything what needed to be done, but it left SortDialog without any reference to the layout, therefore layout() returned zero.
That's because you didn't create a layout.
Go back to designer and click the form and choose lay out in grid.
If you don't do this, the layout would be 0 and the program will crash.
You have to create a layout, like QVBoxLayout.
QVBoxLayout *layout = new QVBoxLayout;
layout->setSizeConstraint (QLayout :: SetFixedSize);
setLayout(layout);
I fixed this with changing in Designer Form. Make sure that the layout in the Qt Designer is good. Especially "Form -> Adjust Size" at the end. (in the book page 33; creating a "Form-> Lay Out in a Grid"). Use the original code from the book.

Name and implementations of the special "+" tab

I have always been wondering whether the special "+" tab used to add other tabs (as in internet browsers) had a special name.
Also, is there any popular framework (Qt, wxWidgets, etc...) that has a built-in feature for that in its Notebook/TabWidget?
EDIT: Some asked why would such a feature exist while it's simple to implement it. Well, the answer is simple: every widely used feature deserve a dedicated component. It may be simple to implement in a classic tab widget, but it becames harder to do when we can move the tabs (this special one should always be the last) or when it's possible to close the tabs without having to have them selected (in some tab widgets, there's a cross to close the tab on every tab).
Well, considering the different frameworks, it may be simpler or harder to implement. Hence this question to know whether the feature is standard enough to have a dedicated name and some "built-in" implementations in some frameworks :)
As for current versions of WPF, Winform and Qt there is not any tab control with such a feature, but it could be added easily.
check links for similar examples in WPF and Winform.
With Qt you can use code like this:
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
connect(ui->tabWidget, SIGNAL(currentChanged(int)), this, SLOT(changedTab(int)));
}
void MainWindow::changedTab(int tabId) {
if (tabId == ui->tabWidget->count() - 1) {
QWidget *newTab = new QWidget;
ui->tabWidget->insertTab(tabId, newTab, "new label");
ui->tabWidget->setCurrentIndex(tabId);
}
}
For close tab see setTabsClosable()

setCentralWidget not declared in scope

#include <QtGui>
#include <QWidget>
#include "notepad.h"
notepad::notepad()
{
textField = new QTextEdit;
setCentralWidget(textField);
setWindowTitle(tr("The building of a notepad...."));
}
This is a file of one of my Qt project. There is some error with the setCentralWidget part. The error is that it is not declared in the scope. But I have included the QWidget class under which it gets included. What is the mistake?
setCentralWidget is a method on QMainWindow. It is not a top-level function. It would only be in scope here if your notepad class derives from QMainWindow, which I guess it must not.
Like others have said, setCentralWidget(..) is only a member of QMainWindow. I think the behavior you are looking for can be achieved by adding a layout to your QWidget and then adding your QTextEdit to the layout. I would suggest a QPlainTextEdit as it is setup for editing multiple lines of a text document. QTextEdit is usually used for single line input. Here's some sample code:
notepad::notepad()
{
QVBoxLayout *layout = new QVBoxLayout();
QPlainTextEdit *textBox = new QPlainTextEdit();
layout->addWidget(textBox);
this->setLayout(layout);
setWindowTitle(tr("The building of a notepad...."));
}
The layout can be a QVBoxLayout, QHBoxLayout, QGridLayout, etc. It all depends on what you want to achieve with the layout of the form. You can also add to your existing layout by using this->addWidget(QWidget*) instead of using a newly created layout. I hope this helps.

Resources