Force Tabbed Dock in QMainWindow Qt5.7 - c++

I'm trying to get my QMainWindow to allow only tabbed QDockWidgets. If I understood the Qt Documentation right it should work with the setDockOptions-method.
The following code didn't work for me:
QMainWindow window;
window.setDockOptions(QMainWindow::ForceTabbedDocks);
What am I doing wrong? Or is it a bug in the current Qt version? I'm coding on a MacPro an I'm using Qt 5.7.
thanks

ForceTabbedDocks only applies to user interactions with the docks.
To programatically add new docks in tabs, you need to use QMainWindow::tabifyDockWidgets. For example,
void MainWindow::addTabbedDock(Qt::DockWidgetArea area, QDockWidget *widget)
{
QList<QDockWidget*> allDockWidgets = findChildren<QDockWidget*>();
QVector<QDockWidget*> areaDockWidgets;
for(QDockWidget *w : allDockWidgets) {
if(dockWidgetArea(w) == area) {
areaDockWidgets.append(w);
}
}
if(areaDockWidgets.empty()) {
// no other widgets
addDockWidget(area, widget);
} else {
tabifyDockWidget(areaDockWidgets.last(), widget);
}
}

This is the same answer as #Xian Nox, but adapted for python:
def addTabbedDock(self, area: QtCore.Qt.DockWidgetArea, dockwidget: QtWidgets.QDockWidget):
curAreaWidgets = [d for d in self.findChildren(QtWidgets.QDockWidget)
if self.dockWidgetArea(d) == area]
try:
self.tabifyDockWidget(curAreaWidgets[-1], dockwidget)
except IndexError:
# First dock in area
self.addDockWidget(area, dockwidget)

Related

How to make the text of a QComboBox bold, but not the list items?

We have a longstanding convention in our UI that items are shown in bold when they have been changed but the change is not yet committed. Strangely, until now we haven't used any combo boxes, but I have a use for one now and need to implement this behaviour. So I need to programmatically bold (and later un-bold) the text displayed by a closed combo box. However, I don't want to bold the entire list of items in the pop-up. I could accept bolding the selected item in the list if that's easier.
I've seen lots of answers doing almost this, but usually trying to modify the list items rather than the button. I've tried variations on most of them; unfortunately I didn't keep records of what I tried. For what it's worth, my code currently looks like:
myCombo->setStyleSheet(
"QComboBox {font-weight: bold;} "
"QComboBox QAbstractItemView::item {font-weight: normal;}"
);
This turns the button bold, but also the list items. The same behaviour is seen when I apply the normal weight just to the QAbstractItemView without the ::item, and when I tried a different technique based on :open and :closed on the QComboBox.
I will say I'm fairly new to Qt. I am using Qt5 on Fedora 26, but will be deploying to CentOS 7.
It seems that setting the font-style in QComboBox overrides the view's (and it shouldn't, IMHO).
But, when I tried to explicitly set a view to the combo box, this way:
view = new QListView();
myCombo->setView(view);
the stylesheet posted by the OP suddenly worked.
By the way, the new view is different from the original (e.g. has a white background, etc) and I guess the OP isn't happy with that. One could go on styling it, of course, but one would rather prefer a ready to use view, with a consistent style.
Inspecting the default QComboBox view:
QComboBox * combo = new QComboBox();
qDebug() << combo->view();
yelds this:
QComboBoxListView(0x2091880)
So, there is a specific QComboBoxListView class, which is nowhere to be found in documentation and is defined in qcombobox_p.h, not a file one could include, really, but at least we can understand where the issue come from, in the viewOptions overridden method:
QStyleOptionViewItem option = QListView::viewOptions();
option.showDecorationSelected = true;
if (combo)
option.font = combo->font(); // <--- here
return option;
That combo is a private pointer to QComboBox, initialized in construction:
QComboBoxListView(QComboBox *cmb = 0) : combo(cmb) {}
which will always override the view options font with its own.
Let's have a copy of the QComboBoxListView class, edited and renamed:
comboitemview.h
#ifndef COMBOITEMVIEW_H
#define COMBOITEMVIEW_H
#include <QListView>
#include <QComboBox>
class ComboItemView : public QListView
{
Q_OBJECT
QComboBox * _box;
public:
ComboItemView(QComboBox *box);
protected:
void paintEvent(QPaintEvent *event);
void resizeEvent(QResizeEvent *event);
QStyleOptionViewItem viewOptions() const;
};
#endif // COMBOITEMVIEW_H
comboitemview.cpp
#include "comboitemview.h"
#include <QPaintEvent>
#include <QPainter>
ComboItemView::ComboItemView(QComboBox * box = 0) : _box(box){}
void ComboItemView::paintEvent(QPaintEvent *event)
{
if (_box)
{
QStyleOptionComboBox opt;
opt.initFrom(_box);
opt.editable = _box->isEditable();
if (_box->style()->styleHint(QStyle::SH_ComboBox_Popup, &opt, _box))
{
QStyleOptionMenuItem menuOpt;
menuOpt.initFrom(this);
menuOpt.palette = palette();
menuOpt.state = QStyle::State_None;
menuOpt.checkType = QStyleOptionMenuItem::NotCheckable;
menuOpt.menuRect = event->rect();
menuOpt.maxIconWidth = 0;
menuOpt.tabWidth = 0;
QPainter p(viewport());
_box->style()->drawControl(QStyle::CE_MenuEmptyArea, &menuOpt, &p, this);
}
}
QListView::paintEvent(event);
}
void ComboItemView::resizeEvent(QResizeEvent *event)
{
resizeContents(viewport()->width(), contentsSize().height());
QListView::resizeEvent(event);
}
QStyleOptionViewItem ComboItemView::viewOptions() const
{
QStyleOptionViewItem option = QListView::viewOptions();
option.showDecorationSelected = true;
return option;
}
And finally use it to style the view font:
myCombo->setView(new ComboItemView(myCombo));
myCombo->setStyleSheet(
"QComboBox {font-weight: bold;} "
"QComboBox QAbstractItemView {font-weight: normal;}"
);

The inferior stopped because it received signal from the Operating System error on resizable scrollarea

I have a QScrollArea inside QTabWidget and I have a QWidget beside my QTabWidget. I want QScrollArea to be resized when my main window is resized, so I have made this code like this:
void frmSummaryContact::on_btnAddNewContact_clicked()
{
MainWindow *mnWindow = qobject_cast<MainWindow *>(this->parent()->parent()->parent()->parent()->parent()->parent());
QTabWidget *tbWidget = qobject_cast<QTabWidget *>(this->parent()->parent()->parent()->parent());
frmDetailContact *frm = new frmDetailContact(mnWindow, "input", -1, mnWindow->rightPane());
QScrollArea *scrlForm = new QScrollArea;
scrlForm->setWidgetResizable(true);
scrlForm->setWidget(frm);
mnWindow->AddNewTab(tbWidget, scrlForm, "Add Contact");
}
my QTabWidget is in different form, so I cast it with qobject_cast. Meanwhile in another form, I have a toogle button to hide QWidget so my QTabWidget get wider. So in that form I have a code like this:
void frmDetailContactToggle::on_btnSearch_clicked()
{
MainWindow *mnWindow = qobject_cast<MainWindow *>(this->parent()->parent()->parent());
QLayoutItem *child;
while ((child = mnWindow->rightPane()->layout()->takeAt(0)) != 0)
child->widget()->setVisible(false);
mnWindow->rightPane()->setVisible(false);
QScrollArea *scrlContent = qobject_cast<QScrollArea *>(mnWindow->tabContentWidget()->currentWidget());
scrlContent->setWidgetResizable(false);
mnWindow->tabContentWidget()->setGeometry(mnWindow->tabContentWidget()->x(), mnWindow->tabContentWidget()->y(), m_width - mnWindow->tabContentWidget()->x() - 10, mnWindow->tabContentWidget()->height());
scrlContent->setWidgetResizable(true);
m_showRightPane = false;
}
I have realized that I can't change the geometry when WidgetResizable is true. It showed "The inferior stopped because it received signal from the Operating System" error. So I thought about making it false, changing the geometry, and making it true again. But when I want to make it true, I encounter the same error. Could anyone please help me to solve my problem?
if your program used uninitialized pointers,that may causes SIGSEGV.

How to change window title and central widget in Qt?

Hi, I have a problem with changing window title and central widget in Qt.
There is MainWindow:
class MainWindow : public QMainWindow
{
// (...)
QStackedWidget* widgets;
Quiz* widget1, *widget2;
}
and there is a class Quiz:
class Quiz : public QWidget
{
public slots:
void myClicked();
}
I wanted to change MainWindow title after clicking on button, which is a element of Quiz (and it is connected with slot myClicked).
void Quiz::myClicked()
{
static_cast<MainWindow>(parent).myFunction();
}
void MainWindow::myFunction()
{
widget2 = new Quiz(this,2);
widgets->addWidget(widget2);
std::cout<<"current wdgt: " << widgets->currentIndex() << std::endl; // shows: 0
widgets->setCurrentWidget(widget2);
std::cout<<"current wdgt " << widgets->currentIndex() << std::endl; // shows: 1
setWindowTitle("newTitle");
std::cout<<"Title is " << windowTitle().toStdString() << std::endl;
}
So widgets->currentIndex shows index of new widget but nothing is changed in my window. The same problem is with window title - method windowTitle() returns new title, but title on a titlebar is old. Why?
If I change title in Quiz::myClicked by:
parent->setWindowTitle("newTitle");
it works! Why it works how strange? Please help.
it works! Why it works how strange? Please help.
It is not strange. That is how the Qt API is designed. See the documentation for the explanation:
windowTitle : QString
This property holds the window title (caption).
This property only makes sense for top-level widgets, such as windows and dialogs.
Let us analyze the last sentence: your quiz is neither a QMainWindow, nor a QDialog, hence it cannot work. Windows titles only make sense for those based on the documentation. When you call it on the parent, it will work respectively since that is a QMainWindow.
The title bar shows the title of the MainWindow. Your Quiz widgets are "inside" the MainWindow, so their titles are not shown.
If you want to change the title bar text, you must call MainWindow::setWindowTitle().

Qt QScrollArea autoscroll

I'm having problems with QLabel and QScrollArea. I'm trying to make QScrollArea to scroll automatically, but can't find any information about it..
Firstly, I'm using QLabel inside QScrollArea, then QLineEdit outside from QScrollArea. When I type text in QLineEdit, it writes to QLabel and the new line. Whenever it reaches to end of area, QScrollArea doesn't scroll automatically.. How can I do that?
Thank you.
Can't you use QLineEdit itself instead of Qlabel(if u are using only text)?, so that you dont have to use QScrollArea also.
[edit]
What if you set the verticalSlider position to Label->height()
void MainWindow::on_lineEdit_returnPressed()
{
ui->label->setText(ui->label->text() + ui->lineEdit->text() + "\n");
ui->ScrollArea->verticalScrollBar()->setSliderPosition(label->height())
}
Take a look at this example: http://qt-project.org/forums/viewthread/23790/
Without to see your code that is difficult to be more precise ...
[EDITED] Try this:
void MainWindow::on_lineEdit_returnPressed()
{
ui->label->setText(ui->label->text() + ui->lineEdit->text() + "\n");
ui->lineEdit->moveCursor (QTextCursor::Start) ;
ui->lineEdit->ensureCursorVisible() ;
...
}

How to make a QMdiArea subwindow widget non-resizeable?

So the non-QMdiArea version of my code,
MyWidget::MyWidget(QWidget* parent)
{
...
layout()->setSizeConstraint( QLayout::SetFixedSize );
}
MainWindow::MainWindow(...)
{
...
MyWidget* wgt = new MyWidget(NULL);
wgt->show();
}
works just fine and produces a widget that the user can't resize. But when the MainWindow code is replaced with
MainWindow::MainWindow(...)
{
...
MyWidget* wgt = new MyWidget(ui->mdiArea); //Or MyWidget(NULL), same result
ui->mdiArea->addSubWindow(wgt);
}
the window, now within the QMdiArea, is resizeable. It doesn't seem to be an issue of Qt::WindowFlags, they don't handle resize policy. Surely there is a way to do this? NB I cant use something like setFixedSize(ht, wd) since the size of the widget can change programmatically (subwidgets are added and removed). But the user should not be able to resize it.
Even though MyWidget is not resizeable, when you call:
ui->mdiArea->addSubWindow(wgt);
The widget is put in a QMdiSubWindow which is resizeable. All you have to do is get the window that's created and fix its size:
QMdiSubWindow* subWindow = ui->mdiArea->addSubWindow(wgt);
subWindow->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
This should work, but I haven't tried this code myself.
EDIT: well... apparently that doesn't fix the size. :(
The following worked for me:
MyWidget* wgt = new MyWidget(ui->mdiArea);
QMdiSubWindow* subWindow = ui->mdiArea->addSubWindow(wgt);
subWindow->setFixedSize(wgt->size());
wgt->show();