QTabWidget methods not available in QtDesigner - qt

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)

Related

Qt shortcut for custom context menu

I have been reading though a couple of examples and post but I just cannot figure out how to add a shortcut to my custom context menu. My GUI has several elements. One of them is a treeView. For the elements in my treeView I would like to have a custom context menu.
My first approach was according to this tutorial here. The context menu itself worked but the shortcuts cannot work if you create the actin within the show function.
So my second approach was according to this tutorial. But still my shortcuts do not work and if I use the context menu all actions are called twice...
Since I did not find a tutorial or code example, which matches my case, I hope that someone here can explain to me how this is correctly done in theory. Adding a shortcut to an action for a custom context menu.
Where do I have to declare my action?
What needs to be the parent of the action?
On which widget do I need to call addAction?
Thanks for any hints.
Another way is to add your action also to the parent widget (or main window widget). As mentioned in this reply, adding the same action to multiple widgets is fine and it's the way QActions are supposed to be used.
Example with custom HtmlBrowser class deriving from QTextBrowser:
Ctrl+U shortcut works for this code:
HtmlBrowser::HtmlBrowser(QWidget * parent) : QTextBrowser(parent)
{
viewSourceAct = new QAction(tr("View/hide HTML so&urce"), this);
viewSourceAct->setShortcut(tr("Ctrl+U"));
viewSourceAct->setCheckable(true);
parent->addAction(viewSourceAct);
connect(viewSourceAct, &QAction::triggered, this, &HtmlBrowser::viewSourceToggle);
}
and Ctrl+U shortcut does not work with this code (same as above, but without parent->AddAction(...)):
HtmlBrowser::HtmlBrowser(QWidget * parent) : QTextBrowser(parent)
{
viewSourceAct = new QAction(tr("View/hide HTML so&urce"), this);
viewSourceAct->setShortcut(tr("Ctrl+U"));
viewSourceAct->setCheckable(true);
connect(viewSourceAct, &QAction::triggered, this, &HtmlBrowser::viewSourceToggle);
}
Curiously, parent in this case is another widget (tab widget), not MainWindow. Still, adding parent->addAction() helps. And, unlike your suggested answer, it works even when connecting action to simple methods, without slots. Works for me in Qt 5.15.0. Not quite sure why it works, though. Perhaps, the widget the action is added to must be permanent for shortcuts to work? Looks like a bug in Qt.
Thanks to Scheff's hint I got it working. I do not now if this is really the correct way but this works for me.
The action needs to be declared in the constructor of your GUI class (e.g. MainWindow):
actionDel = new QAction(tr("delete"), this);
actionDel->setShortcut(QKeySequence(Qt::Key_Delete));
connect(actionDel, SIGNAL(triggered()), this, SLOT(actionDel_triggered()));
The triggered signal needs to be connected to a slot. Hint: if you create the slot do not use on_ACTIONNAME_triggered, this will interfere with the designer and cause a connection error.
Next add the action to a custom menu
fileContextMenu = new QMenu(this);
fileContextMenu->addAction(actionDel);
And to the widget
ui->treeView->setContextMenuPolicy(Qt::CustomContextMenu);
connect(ui->treeView, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(showDirContextMenu(QPoint)));
ui->treeView->addAction(actionDel);
All in the constructor of your GUI class.
To show the context menu use the following code in slot used in the above connect:
QModelIndex index=ui->treeView->indexAt(pos);
// Here you can modify the menu e.g. disabling certain actions
QAction* selectedItem = fileContextMenu->exec(ui->treeView->viewport()->mapToGlobal(pos));
If you do not have a slot for an action, the action can be also handled in the context menu slot, but this does not work with shortcuts!
if(selectedItem == actionOpen){
on_treeView_doubleClicked(index);
}

SIGSEGV when adding widget in 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

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()

How can I change the side on which a Qt::Drawer opens on Mac?

Greetings!
I have a QDialog myDialog; and want to attach additional information to it using QWidget myDrawer( &myDialog, Qt::Drawer ). This works fine, except that the drawer always attaches itself to the left side of myDialog. I need it on the right side. And I have no clue how to do that.
Any hints and ideas would be greatly appreciated!
Thanks, and best regards,
Robin
This is normally done by the OS. Try moving the window close to the left edge of your screen and open the drawer - it should now open on the right-hand side.
Generally, try to avoid using drawers, as they are seemingly being frowned upon and not part of the expected "look and feel" these days anymore.
Update:
Sorry - Correct, they are still in the Human Interace Guidelines, but most developers don't use them anymore. From discussions on several boards and IRC channels it seems that they feel "unnatural" as they are not part of the "window".
To get back to your question; I doubt you can control the side the drawer slides out from Qt. Plus it might make a difference depending on if you are using Cocoa- or Carbon-Qt. At least I couldn't find anything regarding that in the Qt documentation.
In the demos\mainwindow project, there are a few lines (lines 311-314) in mainwindow.cpp:
#ifndef Q_WS_MAC
{ "Black", 0, Qt::LeftDockWidgetArea },
#else
{ "Black", Qt::Drawer, Qt::LeftDockWidgetArea }
I don't have access to OS X right now, but I remember I learnt to change the side of the drawer by the above-mentioned project. So you could playaround with this project in OS X.
this is possible:
but you will have to use QDockWidget as the Qt::Drawer widget;
the following code is from a QMainWindow class:
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
QDockWidget *drawdock = new QDockWidget(this,Qt::Drawer);
this->addDockWidget(Qt::RightDockWidgetArea,drawdock);
}
To change the side of the drawer during runtime:
QMainWindow *mainWindow = qobject_cast<QMainWindow *>(this);
mainWindow->addDockWidget(Qt::BottomDockWidgetArea,drawdock);
The areas could be any one of the DockWidgetAreas

How to know that widget is currently is running in Qt Designer

How can I in code of the custom Qt widget know that it is currently instantiated in Qt designer?
Use case:
I build a complex custom widget that has several child widgets like QPushButton, QLabel etc.
As application logic require, when widget is created most of those sub component are not visible but in design time when I put it on a form I would like to see them.
To be able to play with style sheet at design time.
Currently what I get is a empty is only a result of constructor - minimal view (actually empty in my case).
What I am looking for is to be able to do something like
MyQWidget::(QWidget *parent)
{
....
if(isRunningInDesigner())
{
myChildWidget1->setVisible(true);
myChildWidget2->setVisible(true);
myChildWidget3->setVisible(true);
}
else
{
myChildWidget1->setVisible(false);
myChildWidget2->setVisible(false);
myChildWidget3->setVisible(false);
}
....
}
So what should I put in to this bool isRunningInDesigner() ?
From the Qt Designer manual:
To give custom widgets special behavior in Qt Designer, provide an implementation of the initialize() function to configure the widget construction process for Qt Designer specific behavior. This function will be called for the first time before any calls to createWidget() and could perhaps set an internal flag that can be tested later when Qt Designer calls the plugin’s createWidget() function.
Those are methods from the QDesignerCustomWidgetInterface plugin interface. In short: you tell the widget to behave differently when Qt Designer asks your plugin to create instances of your custom widget.

Resources