No icon with QStyleOptionButton - c++

I have got a weird problem.
I need to have some buttons in my QTableView. I used to use QAbstractItemView::setIndexWidget() method, but it is not very responsible when working with larger models. Therefore I decided to switch to QStyledItemDelegate. My buttons have icons (and icons only, no text). When working with setIndexWidget, I used the following code:
ClientDetailsButton::ClientDetailsButton(const Client* _client,
QWidget* _parent) :
QPushButton("", _parent),
__current(_client) {
setIcon(QIcon(":/uiIcons/button-details.png"));
}
And it worked perfectly. But when I switch to delegate, I use it like that:
QStyleOptionButton button;
button.rect = _option.rect;
button.text.clear();
button.icon = QIcon(":/uiIcons/button-details.png");
button.state = _option.state | QStyle::State_Enabled;
if (_index == __button)
button.state |= QStyle::State_Sunken;
QApplication::style()->drawControl(QStyle::CE_PushButton, &button, _painter);
The button itself is fine, but its empty. There is no icon visible. Suprisingly, when I use, for example:
button.icon = QIcon::fromTheme("dialog-information", QIcon(":/uiIcons/button-details.png"));
the theme icon is visible. But if Qt cannot find the theme icon, the replacement is still blank. I tried everything I could think of and have no idea why it doesn't work. Anyone has any ideas?

I solved this problem by setting button.iconSize=QSize(16,16); as the default iconsize is (-1,-1) so the icon is invisible.

Related

QGraphicsScene, QTextEdit and lost focus

QTextEdit and similar widgets embedded in QGraphicsScene lose focus after using standard context menu (copy/paste), i. e. you need to click on QTextEdit again to continue editing. Scene emits focusItemChanged with newFocusItem==0.
First question: Is it a bug or standard behavior?
My investigation shows that function QGraphicsItemPrivate::setVisibleHelper() clears focus here:
if (hasFocus && scene) {
// Hiding the focus item or the closest non-panel ancestor of the focus item
QGraphicsItem *focusItem = scene->focusItem();
bool clear = true;
if (isWidget && !focusItem->isPanel()) {
do {
if (focusItem == q_ptr) {
clear = !static_cast<QGraphicsWidget *>(q_ptr)->focusNextPrevChild(true);
break;
}
} while ((focusItem = focusItem->parentWidget()) && !focusItem->isPanel());
}
if (clear)
clearFocusHelper(/* giveFocusToParent = */ false, hiddenByPanel);
}
QGraphisItem has undocumented (internal) flag QGraphicsItem::ItemIsFocusScope. If the flag is set for QTextEdit's proxy-item it gets focus back after menu, but in any case focus cleared at first and after that Item receives it again or not.
Second Question: What is flag QGraphicsItem::ItemIsFocusScope for?
Looks like QGraphicsItem::ItemIsFocusScope is for FocusScope QML item. QtQuick1 is QGraphicsScene based and used that flag.
I'm not sure about side effects but that helps:
auto edit = new QLineEdit();
auto item = scene->addWidget(edit);
item->setFlag(QGraphicsItem::GraphicsItemFlag::ItemIsPanel);
Tested on Qt 5.9, Linux
EDIT
For me looks as bug:
add QLineEdit to scene
click to focus QLineEdit
hit ContextMenu key to show context menu
hit Esc key to exit context menu
try to type
Expected: QLineEdit is focused and text appears
Actual: QLineEdit lost input focus
Please find it or report with Qt bug tracker
So it's OK to have workaround using QGraphicsItem::ItemIsFocusScope flag for example.
#if (QT_VERSION < QT_VERSION_CHECK(<fixed in Qt version>))
// it's workaround of bug QTBUG-...
# if (QT_VERSION == QT_VERSION_CHECK(<version you are develop with>)
item.setFlag(QGraphicsItem::ItemIsFocusScope);
# else
# error("The workaround is not tested on this version of Qt. Please run tests/bug_..._workaround_test")
# endif

Close button only on active tab of QTabWidget

To save space in a QTabWidget, I would like to show the close icon only for the current tab, like e.g. Firefox is doing:
Is there a simple way using a style sheet, some thing like (not working like this)
QTabBar::tab::!selected::close-button {visible: false;}
or do I have to subclass QTabWidget to get the desired behavior?
You won't need to subclass anything, you can use QTabWidget::tabBar() method to obtain a reference (i.e. QTabBar *) to the tab bar associated with your QTabWidget. (Note that this method is no longer protected, so it can be accessed without subclassing the class)
QTabBar *tabBar = tabWidget->tabBar();
You can now use tabBar reference to hide close buttons on non-current tabs. For example to hide ith button, you can do:
tabBar->tabButton(i, QTabBar::RightSide)->hide();
So a simple workflow could be as follows:
Connect QTabWidget::currentChanged(int index) signal to a slot.
In that slot hide all close buttons other than the button at index.
You can subclass QTabWidget to get access to the QTabBar widget using protected method QTabWidget::tabBar. Then you can connect to the QTabBar::currentChanged signal and hide close button for not selected tabs manually:
QTabBar::ButtonPosition closeSide =
(QTabBar::ButtonPosition)style()->styleHint(QStyle::SH_TabBar_CloseButtonPosition, 0, this);
for (int i = 0; i < toolbar->count(); ++i)
{
if (i != toolbar->currentIndex())
{
QWidget *w = toolbar->tabButton(i, closeSide);
w->hide();
}
}
hide() leaves empty space for the invisible close button. This looks funny.
Set the width to 0 instead.

Issue with QLayout with QStackedWidget

I am implementing a tab style UI. where tabs are shown by QListWidget and contents are shown by QStackedWidget. on every page of QStackWidget there is layout which allow to insert panel(widget) in QHBoxlayout. at every panel, there are couple of icons which are again in QHBoxLayout. Below is ideal case which I wanted to implement.
But on other page of QStackWidget this is not the case (with less icons) as below
I want to remove extra space ( or align icon to left to eliminate extra space among icons on panels)
I tried spacer, then this happened :(
please help me to correct this thing. My spacer code is as
inline QSpacerItem * buildSpacer(Qt::Orientation orientation)
{
QSpacerItem * pSpacer = nullptr;
if (orientation == Qt::Horizontal)
{
pSpacer = new QSpacerItem(1000, UNIT_VALUE, QSizePolicy::Expanding, QSizePolicy::Minimum);
}
else
{
pSpacer = new QSpacerItem(UNIT_VALUE, 1000, QSizePolicy::Minimum, QSizePolicy::Expanding);
}
return pSpacer;
}
Note
I donot want to use QTabWidget. By the way this issue is also with QTabWidget
Why not using QTabWidget in the first place?
Anyway, instead of creating the QSpacerItem by yourself, you should use addStretch():
my_layout->addWidget(new Widget("widget1"));
my_layout->addWidget(new Widget("widget2"));
my_layout->addStretch(1); // will "eat" extra space

How to avoid mouse click on one widget triggering the signals in others in Qt?

In my app I'm using a QTableView to show a list of images and I select some of the images by clicking left mouse button and pressing control keyboard button when I do so the app looks as the below stated image:
But then when I try to use other buttons on the app like "Destination" and then try to select a destination folder then the app looks like this below:
Problem occurs when I click the "select folder" button and try to select the folder. What happens is that click on the folder selection tab, triggers QTableView widget in which I show the image and the deselects all the selected images. I want to avoid it. The way I now track the left mouse button clicks on QTableView widget is as below:
bool MainWindow::eventFilter(QObject* obj, QEvent *ev)
{
if(obj == ui->listOfImages->viewport())
{
QMouseEvent * mouseEv = static_cast<QMouseEvent*>(ev);
if((mouseEv->buttons() & Qt::LeftButton) && (QApplication::keyboardModifiers().testFlag(Qt::ControlModifier) == true))
{
controlButtonCounter++;
fetch = true;
return QObject::eventFilter(obj,ev);
}
else if((mouseEv->buttons() & Qt::LeftButton) && (QApplication::keyboardModifiers().testFlag(Qt::ControlModifier) == false))
{
if(selectedImages.size()>0)
{
ui->listOfImages->clearSelection();
selectedImages.clear();
}
fetch = false;
controlButtonCounter = 0;
}
}
return QObject::eventFilter(obj,ev);
}
Here ui->listOfImages is the QTableView widget. Other things like controlButtonCounter are irrelevant in taking the mouse clicks, I use it for other purposes.
Please say me how I can avoid triggering QTableView widget when I'm pressing on other things that fall in the same region as the QTableView.
if(obj = ui->listOfImages->viewport())
You are not doing a comparison there, you are assigning a value to the obj variable.
It should be like this:
if(obj == ui->listOfImages->viewport())
I'm not sure but maybe it can help you:
void setWindowModality(Qt::WindowModality windowModality)
This property holds which windows are blocked by the modal widget.
This property only makes sense for windows. A modal widget prevents widgets in other windows from getting input. The value of this property controls which windows are blocked when the widget is visible. Changing this property while the window is visible has no effect; you must hide() the widget first, then show() it again.
By default, this property is Qt::NonModal.

Qt: How to display selected text in an inactive window

I have an inactive QMainWindow with a QTabWidget as CentralWidget which holds multiple QPlainTextEdits. Beside that I have a seperate QWidget flagged with Qt::WindowStaysOnTopHint and Qt::Tool which I want to use as a find/replace tool for the QPlainTextEdits.
Now when I use the tool widget the QMainWindow is shown as inactive like it should and the selection background of the selected text in the active QPlainTextEdit is rendered as inactive (slightly grey) but I want the selection to be rendered like the QMainWindow would be active, with the default selection color w/o loosing the focus on the tool widget.
How do I achieve that?
Try something this:
QPalette p = myInactiveWidget->palette();
for (int colorRole=0; colorRole<QPalette::NColorRoles; colorRole++) p.setColor(QPalette::Inactive, colorRole, p.color(QPalette::Active, colorRole));
myInactiveWidget->setPalette(p);
That should make (myInactiveWidget)'s inactive-color-palette the same as its active-color-palette, so that it no longer looks inactive. Or if all you care about is the color of the text-selection-block, then this would probably be sufficient:
QPalette p = myInactiveWidget->palette();
p.setColor(QPalette::Inactive, QPalette::Highlight, p.color(QPalette::Active, QPalette::Highlight));
p.setColor(QPalette::Inactive, QPalette::HighlightedText, p.color(QPalette::Active, QPalette::HighlightedText));
myInactiveWidget->setPalette(p);