Как поместить один виджет поверх другого?
В главный контейнер main_box попадают кнопка btn и цветной контейнер box.
В box я добавляю четыре виджета:
self.back_picture- изображение, которое располагается в верхней части контейнера, полученное с помощью классаBackPicture. Кнопкаbtn, привязанная к методуremakeклассаMyWindow, меняет картинку вself.back_picture. Это очень важно, так как говорит о непостоянности содержимогоself.back_picture.self.round_picture- изображение с закругленными краями, полученное с помощью классаRoundPicture. Подобноself.back_picture, картинка вself.round_pictureбудет в дальнейшем меняться. Я не стал добавлять эту возможность сейчас, чтобы не загромождать код.- Два виджета
QLabel-label1иlabel2, которые не выполняют никаких прямых функций, но нужны для понимания того, как контейнерboxрасполагает внутри себя виджеты.
Окно приложения:
Я нарисовал схему того, что мне теперь нужно(ниже будет описание):
round_pictureрасполагается надback_picture.- Расстояние между левой границей
boxиround_pictureравно расстоянию междуround_pictureи правой границейbox. Эти расстояния постоянны. back_pictureостается на своем месте - в самом верху контейнераbox1. Между верхней границейboxи виджетом нет абсолютно никакого расстояния. Так должно быть при любом размере окна.- Между
round_pictureи верхней границейbox1добавляется растяжимое пространство stretch = 3. - Между
round_pictureиlabel1добавляется растяжимое пространство stretch = 3. - Между
label1иlabel2добавляется растяжимое пространство stretch = 1. - Между
label2и нижней границейbox1добавляется растяжимое пространство stretch = 3. - Возможность менять картинки на
round_pictureиback_pictureдолжна сохраниться.
Фон виджетам label1 и label2 на схеме я добавил, чтобы было лучше видно. В реальности фона нет, но он и не нужен.
Пожалуйста, помогите мне расположить виджеты так, как я описал
from PyQt5 import QtCore, QtWidgets, QtGui
class RoundPicture(QtWidgets.QLabel):
clicked = QtCore.pyqtSignal()
def __init__(self, picture, x, *args, **kwargs):
super(RoundPicture, self).__init__(*args, **kwargs)
self.setFixedSize(x, x)
self.x = x
self.radius = 15
self.setPicture(picture)
def setPicture(self, picture):
target = QtGui.QPixmap(self.size())
target.fill(QtCore.Qt.transparent)
p = QtGui.QPixmap(picture).scaled(
self.x, self.x, QtCore.Qt.KeepAspectRatioByExpanding,
QtCore.Qt.SmoothTransformation
)
painter = QtGui.QPainter(target)
painter.setRenderHint(QtGui.QPainter.Antialiasing, True)
painter.setRenderHint(QtGui.QPainter.HighQualityAntialiasing, True)
painter.setRenderHint(QtGui.QPainter.SmoothPixmapTransform, True)
path = QtGui.QPainterPath()
path.addRoundedRect(0, 0, self.width(), self.height(), self.radius, self.radius)
painter.setClipPath(path)
painter.drawPixmap(0, 0, p)
self.setPixmap(target)
painter.end()
target = None
def mouseReleaseEvent(self, event):
self.clicked.emit()
class BackPicture(QtWidgets.QLabel):
def __init__(self, picture, x, *args, **kwargs):
super(BackPicture, self).__init__(*args, **kwargs)
self.setFixedSize(x, x)
self.x = x
self.setPicture(picture)
def setPicture(self, picture):
self.setPixmap(QtGui.QPixmap(picture).scaled(self.x, self.x, QtCore.Qt.KeepAspectRatio))
class MyWindow(QtWidgets.QWidget):
def __init__(self, parent = None):
super().__init__(parent)
self.index = 1
main_box = QtWidgets.QHBoxLayout(self)
btn = QtWidgets.QPushButton('Remake', clicked = self.remake)
main_box.addWidget(btn)
container = QtWidgets.QWidget()
container.setStyleSheet('background: #2A303D;')
container.setMinimumHeight(300)
container.setFixedWidth(300)
main_box.addWidget(container)
box = QtWidgets.QVBoxLayout(container)
box.setContentsMargins(0, 0, 0, 0)
self.back_picture = BackPicture('picture3.jpg', 300)
box.addWidget(self.back_picture, alignment = QtCore.Qt.AlignCenter)
self.round_picture = RoundPicture('picture1.png', 150)
self.round_picture.setStyleSheet('background: transparent;')
box.addWidget(self.round_picture, alignment = QtCore.Qt.AlignCenter)
label1 = QtWidgets.QLabel('Text number 1')
label1.setStyleSheet(qss)
box.addWidget(label1, alignment = QtCore.Qt.AlignCenter)
label2 = QtWidgets.QLabel('Text number 2')
label2.setStyleSheet(qss)
box.addWidget(label2, alignment = QtCore.Qt.AlignCenter)
box.setStretch(0, 0)
box.setStretch(1, 2)
box.setStretch(2, 2)
def remake(self):
if self.index == 1:
self.back_picture.setPicture('picture2.png')
self.index = 2
else:
self.back_picture.setPicture('picture3.jpg')
self.index = 1
qss = '''QLabel {
color: red;
font: bold 16px;
background: transparent;
}'''
if __name__ == '__main__':
import sys
app = QtWidgets.QApplication(sys.argv)
window = MyWindow()
window.setWindowTitle(' ')
window.show()
sys.exit(app.exec_())
Ответы (2 шт):
Я убрал back_picture из макета. Попробуйте что получилось.
from PyQt5 import QtCore, QtWidgets, QtGui
class RoundPicture(QtWidgets.QLabel):
clicked = QtCore.pyqtSignal()
def __init__(self, picture, x, *args, **kwargs):
super(RoundPicture, self).__init__(*args, **kwargs)
self.setFixedSize(x, x)
self.x = x
self.radius = 15
self.setPicture(picture)
def setPicture(self, picture):
target = QtGui.QPixmap(self.size())
target.fill(QtCore.Qt.transparent)
p = QtGui.QPixmap(picture).scaled(
self.x, self.x,
QtCore.Qt.KeepAspectRatioByExpanding,
QtCore.Qt.SmoothTransformation
)
painter = QtGui.QPainter(target)
painter.setRenderHint(QtGui.QPainter.Antialiasing, True)
painter.setRenderHint(QtGui.QPainter.HighQualityAntialiasing, True)
painter.setRenderHint(QtGui.QPainter.SmoothPixmapTransform, True)
path = QtGui.QPainterPath()
path.addRoundedRect(0, 0, self.width(), self.height(), self.radius, self.radius)
painter.setClipPath(path)
painter.drawPixmap(0, 0, p)
self.setPixmap(target)
painter.end()
target = None
def mouseReleaseEvent(self, event):
self.clicked.emit()
class BackPicture(QtWidgets.QLabel):
def __init__(self, picture, x, *args, **kwargs):
super(BackPicture, self).__init__(*args, **kwargs)
self.setFixedSize(x, x)
self.x = x
self.setPicture(picture)
def setPicture(self, picture):
self.setPixmap(QtGui.QPixmap(picture).scaled(self.x, self.x, QtCore.Qt.KeepAspectRatio))
class MyWindow(QtWidgets.QWidget):
def __init__(self, parent = None):
super().__init__(parent)
self.index = 1
btn = QtWidgets.QPushButton('Remake', clicked = self.remake)
self.container = QtWidgets.QWidget()
self.container.setStyleSheet('background: #2A303D;')
self.container.setMinimumHeight(300)
self.container.setFixedWidth(300)
main_box = QtWidgets.QHBoxLayout(self) # box1 ???
main_box.addWidget(btn)
main_box.addWidget(self.container)
box = QtWidgets.QVBoxLayout(self.container)
box.setContentsMargins(0, 0, 0, 0)
self.back_picture = BackPicture('300_300.png', 300, self.container) # + , self.container
# box.addWidget(self.back_picture, alignment = QtCore.Qt.AlignCenter) # ---
self.back_picture.move(0, 0) # +++
box.addStretch(3) # +++
self.round_picture = RoundPicture('head2.jpg', 150)
self.round_picture.setStyleSheet('background: transparent;')
box.addWidget(self.round_picture, alignment = QtCore.Qt.AlignCenter)
box.addStretch(3) # +++
label1 = QtWidgets.QLabel('Text number 1')
label1.setStyleSheet(qss)
box.addWidget(label1, alignment = QtCore.Qt.AlignCenter)
box.addStretch(1) # +++
label2 = QtWidgets.QLabel('Text number 2')
label2.setStyleSheet(qss)
box.addWidget(label2, alignment = QtCore.Qt.AlignCenter)
box.addStretch(3) # +++
'''
# box.setStretch(0, 0)
box.setStretch(0, 3) # ?
box.setStretch(1, 2)
box.setStretch(2, 2)
box.setStretch(3, 2) # ?
'''
def remake(self):
if self.index == 1:
self.back_picture.setPicture('background.png')
self.index = 2
else:
self.back_picture.setPicture('300_300.png')
self.index = 1
qss = '''QLabel {
color: red;
font: bold 16px;
background: transparent;
}'''
if __name__ == '__main__':
import sys
app = QtWidgets.QApplication(sys.argv)
window = MyWindow()
window.setWindowTitle(' ')
window.show()
sys.exit(app.exec_())
В режиме редактирования файла ресурсов и ui-файла (QtCreator)
- Добавляете картинку в файл ресурсов проекта (файл qrs).
- В режиме редактирования ui-файла выбираете любой виджет и в панеле настроек
находите и нажимаете (на кнопку с тремя точками) в пункте
styleSheet - Там, в выпадающем меню
"Добавить ресурс", выбираете background-image - Слева выбираете
"<Resource Root>"- справа появятся соответствующие картинки из файла ресурсов. Выбираете необходимую картинку. - В поле qss появится следующая запись
background-image: url(...);которую удаляете, предварительно скопировав url(...) - Далее вводите следующую строку
#<имя переменной вашего виджета> {
border-image: url(:</path/to/the/picture.ext>) 0 0 0 0 stretch stretch;
}
таким образом вы заполните вашей картинкой весь фон конкретного виджета. Для пропорционального заполнения - поиграйтесь с параметрами border-image, или размерами самого виджета
NB. Без задания имени переменной виджета #<имя переменной вашего виджета> картинка станет фоном у всех дочерних виджетов данного виджета


