Close button only for some tabs in Qt - c++

I am using Qt for an assignment I have for college, and I want to use QTabWidget to display a chat window much like Pidgin's. I want to make the "group chat" tab always open and impossible to close and the rest of the "private channel" tabs closable.
QTabWidget's setTabsClosable(bool) is not helping.
Any ideas?

I found an easier solution, I think.
Simply access the relevant close button and resize it.
tabWidget->tabBar()->tabButton(0, QTabBar::RightSide)->resize(0, 0);

Find the bar (it is private, so use findChild()) and remove the buttons. Documentation claims that close buttons may be placed on left side too.
QTabBar *tabBar = ui->tabWidget->findChild<QTabBar *>();
tabBar->setTabButton(0, QTabBar::RightSide, 0);
tabBar->setTabButton(0, QTabBar::LeftSide, 0);

Hallo,
I guess this post won't help the author of this thread but perhaps someone else wanders over here.
In most cases a non-closable tab should not only ignore the closevent it also should not show a close symbol in its corner. A nice way to reach this is to modify the QTabBar which is inside the QTabWidget.
Example:
// let tabWidget be a QTabWidget with at least one page
QPushButton *closeButton = new QPushButton();
// set icon and size for PushButton, ...
// connect Signal clicked() from closeButton with Slot closeCurrentTab(), ...
// next line sets closeButton in right corner on tab with index 0
tabWidget->tabBar()->setTabButton(0, QTabBar::RightSide, closeButton);

Although tabBar() is indeed protected, Klaus pointed into the right direction. Simply subclass QTabWidget and implement a wrapper method.

You should reimplement your widget's event(Event *e) method, check the type of e, find out CloseEvents, and call parent class's event when you can allow tab to close, or e->ignore() when you do not want it.
Note, then you must parent's event() handle othr events, so do not accept(), reject() or forget them Ж)

I guess you can handle the tabCloseRequest signal and decide whether u'll close a given tab or not
http://doc.qt.io/archives/4.6/qtabwidget.html#tabCloseRequested
Edit: I created a small example to check it out. My example is a simple QtGui application with a mainwindow that has a tabwidget. I then added the tabCloseRequested slot. Here is the code
void MainWindow::on_tabWidget_tabCloseRequested(int index)
{
if(someCondition){
return;
} else if(anotherCondition){
ui->tabWidget->removeTab(index);
}
}
From this example only tabs where the condition doesn't apply will be closed.

The best way for adding a pushbutton to some tabs and not in other is to define a subclass of QTabWidget for taking the QTabBar that is a potected!
The code below is tested and it works:
//TabWidget.h
#ifndef TABWIDGET_H
#define TABWIDGET_H
#include <QTabWidget>
class TabWidget : public QTabWidget {
public:
TabWidget(QWidget *parent);
~TabWidget();
QTabBar *tabBar() const;
};
#endif /* TABWIDGET_H */
//TabWidget.cpp
#include "TabWidget.h"
TabWidget::TabWidget(QWidget * p=0) : QTabWidget(p) {}
TabWidget::~TabWidget() {}
QTabBar * TabWidget::tabBar() const {return QTabWidget::tabBar();}
For using this subclass and create a new tab with a custom button you have to following this instructions ( ui->tabWidget is a QTabWidget with setClosableTabs=false):
TabWidget *t = (TabWidget *) ui->tabWidget;
t->addTab(new QWidget, "empty");
QTabBar *tab = t->tabBar();
QPushButton *b = new QPushButton();
b->setText("x");
tab->setTabButton(tab->count() -1, QTabBar::RightSide, b);
connect(b,SIGNAL(...),this,SLOT(...));

Not sure, why nobody here mentioned the simplest working solution:
tabWidget->tabBar()->setTabButton(0, QTabBar::RightSide, 0);
This completely removes the close button, and the space taken by it.
Documentation

Related

How to make a QTextEdit look disabled

At some point, I need to make a QTextEdit look like it was disabled.
I'm not against calling setEnabled(false), but then the QTextEdit does not receive QContextMenuEvent event anymore (and I need a right-click context menu to be available....because that's how the QTextEdit gets disabled by the user, so that's how I want him to enable it back).
So I do:
QColor mainWindowBgColor = palette().color(QPalette::Window);
// for the current widget
setStyleSheet(QString("background-color: %0").arg(mainWindowBgColor.name(QColor::HexRgb)));
This looks good, unless you right-click the widget and show it's context menu: The context menu appears but looks bad. Item highlighting does not work and then selected text is hardly visible (painted in white on a grey background).
How could I either:
call setEnabled(false) and have right-mouse click context menu be accessible
or use setStyleSheet but make sure it won't be usd by the context menu widget begin painted
or any alternative....
I would try subclassing QTextEdit and overriding contextMenuEvent. There I would show (exec) a standard menu, after changing its stylesheet:
#include <QTextEdit>
#include <QContextMenuEvent>
#include <QMenu>
class TextEdit : public QTextEdit
{
public:
TextEdit(QWidget* p) : QTextEdit(p){}
protected:
void contextMenuEvent(QContextMenuEvent * event)
{
QMenu * menu = createStandardContextMenu();
menu->setStyleSheet("background-color: gray");
menu->exec(QCursor::pos());
}
};
In the above example I set the menu background color to gray, but the goal of this example is to show one can override the menu style sheet, so to prevent the menu to use the one inherited from its parent.
Style sheets are inherited by all sub-widgets. To make a style sheet apply only to a certain widget (or a type of widgets), you have to specify accessors.
E.g.
setStyleSheet(QString(
"QTextEdit { background-color: %0 }"
).arg(mainWindowBgColor.name(QColor::HexRgb)));

How to resize a QLabel displayed by a QWidgetAction after changing it's text

I use a QWidgetAction to add a header to a context menu (that will also show up on Windows, no matter what style is used, in contrast to addSection(), which does not always actually display the title).
The action's widget is a QLabel. It's text is changed by each invocation of the context menu. The menu is setup in the constructor of my class, and the QWidgetAction is added like so (all m_ variables are member variables declared in the header):
m_contextMenu = new QMenu(this);
m_menuTitle = new QLabel;
m_menuTitle->setAlignment(Qt::AlignCenter);
m_menuTitle->setMargin(4);
QWidgetAction *titleAction = new QWidgetAction(m_contextMenu);
titleAction->setDefaultWidget(m_menuTitle);
m_contextMenu->addAction(titleAction);
m_contextMenu->addSeparator();
When the menu is requested, the text of the label is changed and the menu is displayed like so:
m_menuTitle->setText(tr("%1 „%2“").arg(some_variable, some_other_variable));
...
m_contextMenu->exec(place_to_display);
When the label's text is set for the first time (with a short text the label's text is set to), everything is fine:
but when it's set to some longer text, the size remains the same and the text is cropped:
I tried to fix this, but the only working solution I found was to define the QActions displayed in the menu in the constructor, owned by this, setting the label's text, clearing the menu and adding the actions again, like so:
m_contextMenu->clear();
m_menuTitle->setText(tr("%1 „%2“").arg(some_variable, some_other_variable));
m_contextMenu->addAction(m_menuTitleAction);
m_contextMenu->addSeparator();
m_contextMenu->addAction(m_editAction);
m_contextMenu->addAction(m_deleteAction);
m_contextMenu->exec(place_to_display);
Is there a way to resize the title without rebuilding the menu each time?
The solution is to send a resize event instead:
m_menuTitle->setText(tr("%1 „%2“").arg(some_variable, some_other_variable));
...
QResizeEvent re(new_size, m_contextMenu->size());
qApp->sendEvent(m_contextMenu, &re);
This will set the QMenu's internal itemsDirty flag and will force geometry recalculation when the menu is shown. Note that the new size in the event does not matter, as the menu will aways resize based on its sizeHint()!
The QResizeEvent solution didn't really work for me (with a more complex widget), I found the generic solution by reading the QMenu and QAction source code.
m_widget->installEventFilter(this);
// and in my case m_widget->layout()->setSizeConstraint(QLayout::SetFixedSize);
bool SomeClass::eventFilter(QObject* watched, QEvent* event)
{
if (watched == m_widget && event->type() == QEvent::Resize) {
// Force QMenu to recalculate the geometry of this item
QActionEvent e(QEvent::ActionChanged, this);
qApp->sendEvent(m_contextMenu, &e);
}
...
}
QActionEvent triggers everything we need in QMenu: recalculating geometries, resizing the menu to its new size (if it's visible), etc.
This answer extends user362515's answer.
There is little more effort required if you change the size of a hidden widget action (e.g., because of its menu is currently collapsed).
Create a new class ActionWidget which derives publicly from QWidget.
Then override the showEvent method and implement it like this:
void ActionWidget::showEvent(QShowEvent* event)
{
QResizeEvent resize_event(QSize(), parentWidget()->size());
parentWidget()->adjustSize();
qApp->sendEvent(parentWidget(), &resize_event);
QWidget::showEvent(event);
}
Notice that adjustSize must be called on the parent widget of the action widget and the event must be sent to the parent widget.
Of course, you must also reimplement QWidgetAction::createWidget such that it returns an instance of the ActionWidget-class and make sure that ActionWidget reports a proper (updated) size hint.

How to catch information for Qt designer

I have created a Qdialog box using the Qt creator designer as shown below:
When I need to display it, I'm instantiate the class dialogoverwrite (.cpp, .h and .ui)
DialogOverwrite *OverwriteDialog = new DialogOverwrite;
OverwriteDialog->exec();
OverwriteOption = OverwriteDialog->result()
My issue is that I want to get the QDialogButtonBox result but I do not know how. the current code, returning the result of the OverwriteDialog but it's not returning any QDialogButtonBox::Yes, QDialogButtonBox::YesToAll ...
How to catch the QButtonGroup result and not the QDialog result.
In the same way, If I want to change the label value from "File(s) and/or Folder(s)" to another label, how to access to this QLabel ?
Thanks for your help
When you pressed QDialogButton it was emit signal clicked(QAbstractButton*) by catching this signal you can identify which action button pressed.
Please go through following link it would be help you.
Qt: How to implement QDialogButtonBox with QSignalMapper for non-standard button ??
Well the standard way to do this is to handle the result by connecting it. So you could do:
connect(this, SIGNAL(clickedDialogButton(QAbstractButton*)),
SLOT(dialogButton(QAbstractButton* aButton)));
Next you would create a function in your class called dialogButton (for example) and have that handle the result:
void MyUI::dialogButton(QAbstractButton* aButton) {
// Obtain the standard button
StandardButton button = buttonBox−>standardButton(button);
// Switch on the type of button
switch (button) {
case QDialogButtonBox::YesToAll:
// Do the thing you would like to do here
break;
// add some more cases?
}
}
You could also check for the signal given by the QButtonGroup. Something like: void QGroupButton::buttonClicked(QAbstractButton* button) would work in the same way.

How to disable minimizing by taskbar icon click

I've stumbled across very strange behaviour during work on my program.
I've written custom changeEvent class, which allows me to hide program to SysTray on minimizing.
But when i double click on taskbar app icon, the function goes crazy. It creates 2 to 4 systray icons and on requesting window show again, it just shows main window borders without any content inside.
Here's my changeEvent code:
void MainWindow::changeEvent(QEvent *e) {
QMainWindow::changeEvent(e);
if(e->type()==QEvent::WindowStateChange)
if(isMinimized()) {
trayIcon=new QSystemTrayIcon(QIcon(":/icon/itime.ico"));
connect(trayIcon,SIGNAL(activated(QSystemTrayIcon::ActivationReason)),this,SLOT(on_show(QSystemTrayIcon::ActivationReason)));
QAction *showAction=new QAction("Pokaż",trayIcon);
connect(showAction,SIGNAL(triggered()),this,SLOT(on_show()));
QMenu *trayIconMenu=new QMenu;
trayIconMenu->addAction(showAction);
trayIcon->setContextMenu(trayIconMenu);
trayIcon->show();
this->hide();
}
}
on_show(QSystemTrayIcon::ActivatioReason) SLOT:
void MainWindow::on_show(QSystemTrayIcon::ActivationReason reason) {
if(reason) {
if(reason!=QSystemTrayIcon::DoubleClick)
return;
}
if(this->isMinimized()) {
this->raise();
this->showNormal();
this->setWindowState(Qt::WindowActive);
trayIcon->hide();
}
}
on_show() SLOT is just the same besides that first if.
Soo, I would like to know whether there is any way to disable minimizing of window by taskbar icon click.
If there's none, then maybe you have any ideas what can go wrong in here when doubleclicking on icon in taskbar?
Thanks for help!
I've managed to work around that problem by overloading closeEvent function and leaving alone changeEvent function.
So, I'm using boolean flag to distinct between closing of program by menu item and by clicking "X" button and the rest stays just the same, as posted in my earlier post with one change.
I've moved this whole block of code to window constructor in order to prevent multiple creation of trayIcon, as pointed out by Nicolas.
trayIcon=new QSystemTrayIcon(QIcon(":/icon/itime.ico"));
connect(trayIcon,SIGNAL(activated(QSystemTrayIcon::ActivationReason)),this,SLOT(on_show(QSystemTrayIcon::ActivationReason)));
QAction *showAction=new QAction("Pokaż",trayIcon);
connect(showAction,SIGNAL(triggered()),this,SLOT(on_show()));
QMenu *trayIconMenu=new QMenu;
trayIconMenu->addAction(showAction);
trayIcon->setContextMenu(trayIconMenu);
Thanks for your help!

QMenu item text disappears when icon added

I am attempting to add an icon to my QMenu using Qt Designer, however I realized that my text disappears when my icon is added. Is there any way for me to show my icon next to my text?
It was not supported in Qt 4, maybe it is in Qt5 I haven't checked.
In Designer itself there isn't much you can do. In the code one option is to customize the style to draw both the icon and text:
- sizeFromContents for QStyle::CT_MenuBarItem
- drawControl for QStyle::CE_MenuBarItem
- drawCustomControl for QStyleOptionMenuItem
This is not supported by default, mostly because it is not usual an operation that you wish to achieve in here. Of course, you could always use an image with text included, but that is also hackish, unless you paint the image dynamically and then load it later. Although even that would be quite a bit of work.
In order to do, you will need to fiddle with Qt a bit. This is the closest experiment that I would start off with, personally. I have not had time to check whether it actually works, but there should be something among these lines:
class CustomMenuBarWidget : public QWidget
{
public:
explicit CustomMenuBarWidget(QWidget *parent = Q_NULLPTR)
: QWidget(parent)
, menuBar(new QMenuBar())
{
}
virtual void paintEvent(QPaintEvent *event) {
QStyleOptionMenuItem styleOptionMenuItem;
QIcon icon("path/to/my/icon");
styleOptionMenuItem.icon = icon;
styleOptionMenuItem.text = "Hello World!";
QPainter painter(this);
menuBar->style()->drawControl(QStyle::CE_MenuBarItem, &styleOptionMenuItem, &painter, menuBar);
}
private:
QMenuBar *menuBar;
};
You could probably also have a look at QWidgetAction how to insert custom widgets into toolbars and menubars. I have never used that myself in any serious project, but might be useful to be aware of.