1.Intro
Я работаю в Python 3.7 на Windows 10 и использую PyQt5 для графического интерфейса.В моем приложении я получил QScrollArea()
с массивом кнопок внутри.При нажатии кнопка должна выйти за пределы области.Я использую QPropertyAnimation()
, чтобы показать движение.
2.Минимальный, воспроизводимый пример
Я создал небольшое приложение для тестирования.Приложение показывает маленький QScrollArea()
с кучей кнопок внутри.При нажатии на кнопку она переместится вправо:
![enter image description here](https://i.stack.imgur.com/fWgNj.png)
Вот код:
from PyQt5.QtWidgets import *
from PyQt5.QtGui import *
from PyQt5.QtCore import *
import sys
class MyButton(QPushButton):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.setFixedWidth(300)
self.setFixedHeight(30)
self.clicked.connect(self.animate)
return
def animate(self):
self.anim = QPropertyAnimation(self, b'position')
self.anim.setDuration(3000)
self.anim.setStartValue(QPointF(self.pos().x(), self.pos().y()))
self.anim.setEndValue(QPointF(self.pos().x() + 200, self.pos().y() - 20))
self.anim.start()
return
def _set_pos_(self, pos):
self.move(pos.x(), pos.y())
return
position = pyqtProperty(QPointF, fset=_set_pos_)
class CustomMainWindow(QMainWindow):
def __init__(self):
super().__init__()
self.setGeometry(100, 100, 600, 300)
self.setWindowTitle("ANIMATION TEST")
# OUTER FRAME
# ============
self.frm = QFrame()
self.frm.setStyleSheet("""
QFrame {
background: #d3d7cf;
border: none;
}
""")
self.lyt = QHBoxLayout()
self.frm.setLayout(self.lyt)
self.setCentralWidget(self.frm)
# BUTTON FRAME
# =============
self.btn_frm = QFrame()
self.btn_frm.setStyleSheet("""
QFrame {
background: #ffffff;
border: none;
}
""")
self.btn_frm.setFixedWidth(400)
self.btn_frm.setFixedHeight(200)
self.btn_lyt = QVBoxLayout()
self.btn_lyt.setAlignment(Qt.AlignTop)
self.btn_lyt.setSpacing(5)
self.btn_frm.setLayout(self.btn_lyt)
# SCROLL AREA
# ============
self.scrollArea = QScrollArea()
self.scrollArea.setStyleSheet("""
QScrollArea {
border-style: solid;
border-width: 1px;
}
""")
self.scrollArea.setWidget(self.btn_frm)
self.scrollArea.setWidgetResizable(True)
self.scrollArea.setFixedWidth(400)
self.scrollArea.setFixedHeight(150)
self.scrollArea.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOn)
self.lyt.addWidget(self.scrollArea)
# ADD BUTTONS TO BTN_LAYOUT
# ==========================
self.btn_lyt.addWidget(MyButton("Foo"))
self.btn_lyt.addWidget(MyButton("Bar"))
self.btn_lyt.addWidget(MyButton("Baz"))
self.btn_lyt.addWidget(MyButton("Qux"))
self.show()
return
if __name__== '__main__':
app = QApplication(sys.argv)
QApplication.setStyle(QStyleFactory.create('Plastique'))
myGUI = CustomMainWindow()
sys.exit(app.exec_())
3.Проблема
Когда кнопка перемещается, она остается в QScrollArea()
.Мне нужно было бы получить его поверх всего:
![enter image description here](https://i.stack.imgur.com/433Xa.png)
4.Решение (почти)
Спасибо, @magrif, за то, что направили меня в правильном направлении.Благодаря вашим предложениям у меня что-то получилось.
Поэтому я изменил функцию animate()
на следующее:
def animate(self):
self.anim = QPropertyAnimation(self, b'position')
self.anim.setDuration(3000)
startpoint = self.mapToGlobal(self.pos())
endpoint = self.mapToGlobal(QPoint(self.pos().x() + 200, self.pos().y() - 20))
self.setWindowFlags(Qt.Popup)
self.show()
self.anim.setStartValue(QPointF(startpoint.x(), startpoint.y()))
self.anim.setEndValue(QPointF(endpoint.x(), endpoint.y()))
self.anim.start()
QTimer.singleShot(1000, self.hide)
return
Обратите внимание, что я устанавливаю таймер однократного действия на hide()
Кнопка через одну секунду.Это потому, что цикл событий Qt блокируется, пока эта кнопка ведет себя как «всплывающее окно» (из-за self.setWindowFlags(Qt.Popup)
).В любом случае, таймер однократного срабатывания достаточно хорош для меня.
К сожалению, у меня осталась одна проблема.Когда я нажимаю на первую кнопку Foo , она начинает свою анимацию (почти) с того места, где она находилась изначально.Если я нажимаю на одну из других кнопок - например, Baz - он внезапно спрыгивает примерно на 100 пикселей и начинает отсюда анимацию.
Я думаю, что это как-то связано с startpoint = self.mapToGlobal(self.pos())
функция и тот факт, что эти кнопки находятся в QScrollArea()
.Но я не знаю, как это исправить.
5.Цель
Моя цель - создать меню щелчка правой кнопкой мыши, например:
![enter image description here](https://i.stack.imgur.com/UE23B.png)
Когда пользователь нажимает Хватайте и двигайте , кнопка должна исчезнуть с QScrollArea()
и быстро двигаться к мышке.Когда он достигнет указателя мыши, кнопка должна исчезнуть, и операция drag-and-drop может начаться.
Примечание: Следующий вопросэта тема связана с:
Qt: Как выполнить перетаскивание без удерживания кнопки мыши?