Что мешает переместить этот QWidget?Python

Программы на Python
Ответить
Anonymous
 Что мешает переместить этот QWidget?

Сообщение Anonymous »

Я работаю над медиаплеером (клоном Spotify?) и хочу воссоздать меню «фрикадельки», найденное в песнях
Изображение
и мне нравится, как он свободно плавает рядом с кнопкой с фрикаделькой и остается там.
Моей первоначальной мыслью было использовать диалоговое окно, однако это не похоже на тот способ, которым Spotify реализовал меню, поскольку оно не является отдельным окном. Затем я решил использовать виджет «подполе», чтобы хранить все мои виджеты песен, а затем добавить кнопку в виджете песни, которая будет действовать как якорь (?) для создания меню.
Я создал небольшой макет в отдельном файле, чтобы попытаться заставить это работать, и на данный момент у меня есть кнопка для создания виджета с использованием специального сигнала.
class subBox(QWidget):
def __init__(self, widgets: list[QWidget]):
super().__init__()

layout = QVBoxLayout()
for count, wi in enumerate(widgets):
layout.addWidget(wi)

self.setLayout(layout)

@Slot()
def addWid(self, item: testSong):
# TODO
'''
We have the song object that is part of the overall layout.
Now we can create the meatball menu, and slot it over the list of stuff?
'''
layout = self.layout()
idx = layout.indexOf(item)
if idx == -1:
print("Not present.")
return

button: testSongButton = item.findChild(testSongButton)
if button.findChild(testSongMeatball):
print("Meatball spawned.")
return

item.setStyleSheet("background-color: blue")

meatball = testSongMeatball(button)
meatball.setStyleSheet("background-color: red")
meatball.show()

subBox является центральным виджетом mainWindow и содержит виджет testSong, записанный как:
class testSong(QWidget):
meatballCreated = Signal(QWidget, name="meatballCreated")

meatballDestroyed = Signal(QWidget, name="meatballDestroyed")

def __init__(self, data={"name": "name", "album": "album"}):
super().__init__()
# song needs a label and a meatball?
# Horizontal

# init layout
layout = QHBoxLayout()

label = QLabel(data['name'])
album = QLabel(data['album'])

meatball = testSongButton("Meatball menu")

# connect clicked signal to relay into a meatballCreate signal, passing this widget
# as a param
meatball.clicked.connect(
lambda checked: self.meatballCreated.emit(self))

layout.addWidget(label)
layout.addWidget(album)
layout.addWidget(meatball)

self.setLayout(layout)

Есть много дополнительных вещей, которые можно попытаться имитировать мое настоящее приложение, но главное: testSong содержит две метки и кнопку, при нажатии на которую «порождается» виджет с фрикадельками. subBox.addwid — это слот, который получает виджет testSong и ищет в этом виджете дочернюю кнопку и использует эту кнопку как родительскую для вновь созданного меню с фрикадельками. Я пробовал использовать sizePolicy, sizeHint, updateGeometry и другие, чтобы заставить виджет фрикадельки перемещаться внутри кнопки, но мне не удалось заставить его двигаться.
Изображение
Вот как окно выглядит изначально.
Изображение
А вот (уродливые цвета фона) — после нажатия кнопки, вызывающей меню. Я изменил размер окна, чтобы показать, чем QLabel и QPushButton sizePolicy различаются, и я попытался сделать фрикадельку дочерним элементом QLabel, чтобы посмотреть, поможет ли это. но это не так. Я надеялся изменить размер виджета с фрикадельками, чтобы он был больше виджета с кнопкой, а затем как-то сместить его, но теперь понимаю, что это, вероятно, глупый способ сделать это.
Думаю, я сделаю это вместо этого. попробуйте сделать виджет фрикадельки дочерним элементом subBox и используйте геометрию кнопки, чтобы переопределить метод resizeEvent() фрикадельки, немного осмотревшись. Однако мне все же хотелось бы знать, почему я не могу переместить или изменить размер виджета фрикаделек в детстве? Есть ли что-то, что мне нужно переопределить??
Любая помощь будет приветствоваться, и я надеюсь, что я правильно отформатировал вопрос и в удобном для чтения формате.РЕДАКТИРОВАТЬ: 16.11.24
import sys

from PySide6.QtCore import (Qt, QSize, QPoint, QRect,
Signal, SignalInstance, Slot,
)

from PySide6.QtWidgets import (QWidget, QPushButton, QLabel,
QHBoxLayout, QVBoxLayout,
QMainWindow, QApplication,
QSizePolicy)

class TestSong(QWidget):

meatballCreated = Signal(QWidget, name="meatballCreated")
meatballDestroyed = Signal(QWidget, name="meatballDestroyed")

def __init__(self):
super().__init__()

self.setStyleSheet("background-color: blue")

layout = QHBoxLayout(self)

label = QLabel("Label")

meatball = TestSongButton("Meatball button")

# connect clicked signal to relay into a meatballCreate signal, passing this widget
# as a param
meatball.clicked.connect(
lambda checked: self.meatballCreated.emit(self))

layout.addWidget(label)
layout.addWidget(meatball)

class TestSongButton(QPushButton):
def __init__(self, text):
super().__init__(text)
self.setStyleSheet("background-color: purple")

def resizeEvent(self, event):
return super().resizeEvent(event)

def moveEvent(self, event):
return super().moveEvent(event)

class testSongMeatball(QWidget):
def __init__(self, parent=None):
super().__init__(parent)

layout = QHBoxLayout(self)
text = QLabel("Meatball Menu")
layout.addWidget(text)

def resizeEvent(self, event):
print("Meatball Resized!") # this never prints
return QWidget.resizeEvent(self, event)

def moveEvent(self, event):
print("Meatball Moved!") # this never prints
self.findPlace()
return super().moveEvent(event)

def findPlace(self):
p: SubBox = self.parent()
if p:
# find song item and store its position
item: TestSong = p.findChild(TestSong)
item_pos = item.pos()

# find button within song item and store its position
button: TestSongButton = item.findChild(TestSongButton)
button_pos = button.pos()

# since item sits inside SubBox, the meatball will have the same geometry starting point (I think?)
# So to find the button we need to add them
x,y = item_pos.x(), item_pos.y()
nx,ny, = button_pos.x(), button_pos.y()

# Add co-ordinates to get button's top left corner
meatball_pos = QPoint(x+nx,y+ny)

# Create a QRect with the new position and size of meatball (self)
meatball_geo = QRect(meatball_pos, self.size())
self.setGeometry(meatball_geo)

def sizePolicy(self):
return QSizePolicy(QSizePolicy.Policy.Preferred, QSizePolicy.Policy.Preferred)

def sizeHint(self):
return QSize(70,50)

class SubBox(QWidget):
def __init__(self):
super().__init__()

self.setStyleSheet("background-color: green")
layout = QVBoxLayout(self)
self.setLayout(layout)

@Slot()
def addWid(self, item: TestSong):
layout = self.layout()
idx = layout.indexOf(item)
if idx == -1:
print("Not present.")
return

# If meatball already exists
if self.findChild(testSongMeatball):
print("Meatball already present.")
return

# Create meatball widget
meatball = testSongMeatball(self)
meatball.setStyleSheet("background-color: red")

meatball.findPlace() # find geometry
meatball.show() # show meatball

print("Meatball spawned")

class TestWindow(QMainWindow):
def __init__(self):
super().__init__()

window_widget = QWidget()
window_layout = QVBoxLayout(window_widget)

# Give total layout a label
window_layout.addWidget(QLabel("Window"))

# Create sub-box
sub = SubBox()

window_layout.addWidget(sub)

test_widget = TestSong()

sub.layout().addWidget(test_widget)

test_widget.meatballCreated.connect(
lambda item: sub.addWid(item))

# set window as central
self.setCentralWidget(window_widget)

print(self.layout())

def main():
# Create app
app = QApplication(sys.argv)
window = TestWindow()
window.show()
app.exec()

if __name__ == '__main__':
main()



Подробнее здесь: https://stackoverflow.com/questions/791 ... positioned
Ответить

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

Вернуться в «Python»