C++ Over Qt:Controlling Transparency of Labels and Buttons

C++ over Qt : Controlling transparency of Labels and Buttons

You can set transparency of QLabel or QPushbutton by setting the stylesheet :

ui->label->setStyleSheet("background-color: rgba(255, 255, 255, 0);");
ui->button->setStyleSheet("background-color: rgba(255, 255, 255, 0);");

You can also add background-color: rgba(255, 255, 255, 0); to the styleSheet property of the widget in the designer.

The fourth parameter is alpha. You can also have semi-transparent widgets by setting alpha to some value more than zero :

ui->button->setStyleSheet("background-color: rgba(255, 255, 255, 50);");

Is it possible to set the opacity of qt widgets?

Just use QGraphicsOpacityEffect in order to achieve this effect.

  • Qt4: http://doc.qt.io/qt-4.8/qgraphicsopacityeffect.html
  • Qt5: http://doc.qt.io/qt-5/qgraphicsopacityeffect.html
  • Qt6: https://doc.qt.io/qt-6/qgraphicsopacityeffect.html

Qt: How to add two widgets (say QPushButton) to the status bar, one to the left and other to the right side?

You can add two buttons to a layout in a widget and add the widget to the status bar using QStatusBar::addWidget :

QWidget * widget = new QWidget();
QPushButton * leftBut = new QPushButton("Left");
QPushButton * rightBut = new QPushButton("Right");
QGridLayout * layout = new QGridLayout(widget);
layout->addWidget(leftBut,0,0,1,1,Qt::AlignVCenter | Qt::AlignLeft);
layout->addWidget(rightBut,0,1,1,1,Qt::AlignVCenter | Qt::AlignRight);
ui->statusBar->addWidget(widget,1);

How to add custom widget (with layout) overlapping another custom widget (with layout) pyqt

The main problem is that a widget can only have one layout manager, and it's not possible to set another layout if one already exists. It should also not be responsibility of a child widget to set the layout on a parent.

Another important aspect is that box layouts do not allow overlapping widgets, so the only solution is to use a grid layout and specify the span depending on how the overlapping widgets should be placed.

Considering the above, there are two possibilities: use the grid layout on the widget containing the buttons and add the labels on top of them, or the other way around. In the following example, I'm doing the latter. Note that in this case the widget with the labels will not be the child, but the parent.

class TitleData(QWidget):
def __init__(self,title="Title", data="Data", buttons=None, **kwargs):
super().__init__(**kwargs)
self.title = title
self.data = data

self.title_label = QLabel(self.title)
self.data_label = QLabel(self.data)
for label in self.title_label, self.data_label:
label.setAttribute(Qt.WA_NoSystemBackground)
label.setAttribute(Qt.WA_TransparentForMouseEvents)
label.setAlignment(Qt.AlignHCenter)

self.l = QGridLayout(self)
self.l.addWidget(self.title_label, 0, 0, alignment=Qt.AlignTop)
self.l.addWidget(self.data_label, 1, 0)
self.l.setRowStretch(1, 1)
if buttons:
self.l.addWidget(buttons, 0, 0, 2, 1)
buttons.lower()

class DataDisplay(QWidget):
def __init__(self, **kwargs):
# ...
self.xxx = TitleData(buttons=self.sub_widget)

self.l = QVBoxLayout()
self.l.addWidget(self.xxx)
# ...

Note that the button widget is lowered to ensure that it's put behind the labels.

Please consider that this approach is not very good from the UX perspective, at least with the current implementation: buttons could keep a focus rectangle even if they're flat, and this could make the label difficult to read (imagine letters that have vertical lines or that could become different letters with a vertical line, like "o" becoming a "d" or a "b"). Creating two classes for this is also unnecessary, as you can do the same with a simple class, and you could eventually use stylesheets to improve readability:

class TitleDataButton(QWidget):
clicked = pyqtSignal(int)
def __init__(self, title='Title', data='Data', buttons=True, *args, **kwargs):
super().__init__(*args, **kwargs)
self.title = title
self.data = data

self.title_label = QLabel(self.title)
self.data_label = QLabel(self.data)
for label in self.title_label, self.data_label:
label.setAttribute(Qt.WA_NoSystemBackground)
label.setAttribute(Qt.WA_TransparentForMouseEvents)
label.setAlignment(Qt.AlignHCenter)

layout = QGridLayout(self)
layout.addWidget(self.title_label, 0, 0, 1, 2, alignment=Qt.AlignTop)
layout.addWidget(self.data_label, 1, 0, 1, 2)
layout.setRowStretch(1, 1)

if buttons:
self.right_button = QPushButton()
self.right_button.pressed.connect(self.rightF)
self.left_button = QPushButton()
self.left_button.pressed.connect(self.leftF)

for c, button in enumerate((self.left_button, self.right_button)):
layout.addWidget(button, 0, c, 2, 1)
button.setMinimumSize(30,120)
button.setSizePolicy(QSizePolicy.Minimum, QSizePolicy.Minimum)
button.lower()
button.setFocusPolicy(Qt.NoFocus)

button.setStyleSheet('''
QPushButton {
border: 1px solid transparent;
border-radius: 2px;
}
QPushButton:hover {
border-color: darkGray;
background: lightGray;
}
QPushButton:pressed {
background: darkGray;
}
''')

def rightF(self):
self.clicked.emit(1)

def leftF(self):
self.clicked.emit(-1)

As above, the buttons are lowered so that they're placed under the labels.

QLabel with pixmap: prevent pixmap's color change in disabled state

A (not so complicated) way to achieve that, is to draw the pixmap by yourself. Instead of subclassing QLabel and override paintEvent, you can install an event filter in your label and listen for QPaintEvent's only.

Have the filter:

class Filter : public QObject
{
Q_OBJECT
public:
Filter(): QObject(nullptr) {}
bool eventFilter(QObject *watched, QEvent *event);
};

In its eventFilter method, always return false, but when you draw the pixmap:

#include <QPaintEvent>
#include <QPainter>
#include <QStyle>
bool Filter::eventFilter(QObject *watched, QEvent *event)
{
if(event->type() == QEvent::Paint)
{
QLabel * label = dynamic_cast<QLabel*>(watched);
QPainter painter(label);

QPixmap pixmap = label->pixmap()->scaled(label->size());
label->style()->drawItemPixmap(&painter, label->rect(), Qt::AlignHCenter | Qt::AlignVCenter, pixmap);
return true;
}
return false;
}

Instantiate and install the filter, something like:

ui->setupUi(this);
Filter * filter = new Filter();
ui->label->installEventFilter(filter);

/* don't forget to call:

delete filter;

somewhere later */

In my example code, I scaled the pixmap to fit the label size and centered it both horizontally and vertically, but you can adjust all this, according to your needs.

Moreover, the same filter can be installed to more than one label, since the logic works fine for them all. More on event filtering here.

How to set window and it's graphicScene transparent(using slider) and leave only QPushButton visible

Here is one way.

class MainWindow(QDialog):
def __init__(self):
QDialog.__init__(self)
# these two lines are needed to get a transparent background in windows
self.setWindowFlags(Qt.FramelessWindowHint)
self.setAttribute(Qt.WA_TranslucentBackground)

# rest of class definition unchanged

class MainGraphicsWidget(QGraphicsView):
def __init__(self, parent=None):
super(MainGraphicsWidget, self).__init__(parent)
# set transparent background color for the widget itself
self.setStyleSheet("background-color: #00000000")
self._scene = QGraphicsScene()
self.setScene(self._scene)

# create of slider and connect to slot for changing opacity.
self.transpSlider = QSlider()
self.transpSlider.setStyleSheet('background-color: #00000000')
self.transpSlider.setRange(0,255)
self.transpSlider.valueChanged.connect(self.set_opacity)
self.transpSlider.setValue(255)

# rest of __init__ unchanged

def set_opacity(self, value):
brush = self.backgroundBrush()
color = brush.color()
color.setAlpha(value)
brush.setColor(color)
self.setBackgroundBrush(color)

Note that I've changed the range of the slider to 0-255 to make changing the opacity from fully opaque to fully transparent easier.



Related Topics



Leave a reply



Submit