Pyqt scrollarea не изменен после dragndrop
Укороченная версия:
- возьмите код, запустите его, (все, что вам нужно, это две иконки PNG)
- изменить размер окна, чтобы быть намного больше
- перетащите один из значков далеко (как минимум на 300+ пикселей)
- затем измените размер окна до исходного размера
- затем попробуйте прокрутить, чтобы увидеть значок, который вы перетащили.
- ты не сможешь. потому что скроллария слишком мала.
- Зачем?
длинная версия:
У меня возникли проблемы с выяснением, как обновить прокрутку для отображения добавленного или измененного содержимого в моем приложении.
Я показываю значки, я могу перетаскивать их.
если я увеличу окно, перетащите один значок вниз,
а затем верни мне размер окна,
скролларея не позволяет мне прокручиваться вниз, чтобы увидеть мою иконку.
По сути, после запуска приложения размеры scrollarea никогда не меняются.
Как я могу сделать скроллареа на dragndrop, чтобы обновиться до нового размера?
это может быть больше, как показано на скриншоте ниже,
или меньше, если все мои значки сгруппированы в верхнем левом углу, например..
если содержимое помещается в окне, я не буду показывать слайдер.
вот скриншот, показывающий проблему,
это то же самое окно, я просто изменяю его размер и перетаскиваю один значок внизу:
(scrollarea не обновляется, поэтому я не могу прокрутить вниз к значку, который я поместил внизу)
вот код на данный момент:
#!/usr/bin/python3
from PyQt5.QtGui import *
from PyQt5.QtCore import *
from PyQt5.QtWidgets import *
import sys
class DragWidget(QFrame):
def __init__(self, parent=None):
super(DragWidget, self).__init__(parent)
self.setMinimumSize(200, 200)
self.setAcceptDrops(True)
test_icon1 = QLabel(self)
test_icon1.setPixmap(QPixmap('./images/closeicon.png'))
test_icon1.move(20, 20)
test_icon1.show()
test_icon1.setAttribute(Qt.WA_DeleteOnClose)
test_icon2 = QLabel(self)
test_icon2.setPixmap(QPixmap('./images/openicon.png'))
test_icon2.move(60, 20)
test_icon2.show()
test_icon2.setAttribute(Qt.WA_DeleteOnClose)
def dragEnterEvent(self, event):
if event.mimeData().hasFormat('application/x-dnditemdata'):
if event.source() == self:
event.setDropAction(Qt.MoveAction)
event.accept()
else:
event.acceptProposedAction()
else:
event.ignore()
dragMoveEvent = dragEnterEvent
def dropEvent(self, event):
if event.mimeData().hasFormat('application/x-dnditemdata'):
itemData = event.mimeData().data('application/x-dnditemdata')
dataStream = QDataStream(itemData, QIODevice.ReadOnly)
pixmap = QPixmap()
offset = QPoint()
dataStream >> pixmap >> offset
newIcon = QLabel(self)
newIcon.setPixmap(pixmap)
newIcon.move(event.pos() - offset)
newIcon.show()
newIcon.setAttribute(Qt.WA_DeleteOnClose)
if event.source() == self:
event.setDropAction(Qt.MoveAction)
event.accept()
else:
event.acceptProposedAction()
else:
event.ignore()
def mousePressEvent(self, event):
child = self.childAt(event.pos())
if not child:
return
pixmap = QPixmap(child.pixmap())
itemData = QByteArray()
dataStream = QDataStream(itemData, QIODevice.WriteOnly)
dataStream << pixmap << QPoint(event.pos() - child.pos())
mimeData = QMimeData()
mimeData.setData('application/x-dnditemdata', itemData)
drag = QDrag(self)
drag.setMimeData(mimeData)
drag.setPixmap(pixmap)
drag.setHotSpot(event.pos() - child.pos())
tempPixmap = QPixmap(pixmap)
painter = QPainter()
painter.begin(tempPixmap)
painter.fillRect(pixmap.rect(), QColor(127, 127, 127, 127))
painter.end()
child.setPixmap(tempPixmap)
if drag.exec_(Qt.CopyAction | Qt.MoveAction) == Qt.MoveAction:
child.close()
else:
child.show()
child.setPixmap(pixmap)
class Window(QWidget):
def __init__(self, parent=None):
super(Window, self).__init__()
widget = QWidget()
palette = QPalette()
palette.setBrush(QPalette.Background, QBrush(QPixmap("images/pattern.png")))
widget.setPalette(palette)
layout = QVBoxLayout(self)
layout.addWidget(DragWidget())
widget.setLayout(layout)
scroll = QScrollArea()
scroll.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOn)
scroll.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
scroll.setWidgetResizable(True)
scroll.setWidget(widget)
vlayout = QVBoxLayout(self)
vlayout.setContentsMargins(0, 0, 0, 0)
vlayout.setSpacing(0)
vlayout.addWidget(scroll)
self.setLayout(vlayout)
self.show()
if __name__ == '__main__':
app = QApplication(sys.argv)
window = Window('./')
sys.exit(app.exec_())
1 ответ
Оказалось, мне нужно изменить метод dropEvent,
взять X и Y отброшенного значка и использовать эти значения для setMinimumSize().
как это:
#!/usr/bin/python3
from PyQt5.QtGui import *
from PyQt5.QtCore import *
from PyQt5.QtWidgets import *
import sys
class DragWidget(QFrame):
def __init__(self, parent=None):
super(DragWidget, self).__init__(parent)
self.setMinimumSize(200, 200)
self.setAcceptDrops(True)
self.test_icon1 = QLabel(self)
self.test_icon1.setPixmap(QPixmap('./images/closeicon.png'))
self.test_icon1.move(20, 20)
self.test_icon1.show()
self.test_icon1.setAttribute(Qt.WA_DeleteOnClose)
self.test_icon2 = QLabel(self)
self.test_icon2.setPixmap(QPixmap('./images/openicon.png'))
self.test_icon2.move(60, 20)
self.test_icon2.show()
self.test_icon2.setAttribute(Qt.WA_DeleteOnClose)
def dragEnterEvent(self, event):
if event.mimeData().hasFormat('application/x-dnditemdata'):
if event.source() == self:
event.setDropAction(Qt.MoveAction)
event.accept()
else:
event.acceptProposedAction()
else:
event.ignore()
dragMoveEvent = dragEnterEvent
def dropEvent(self, event):
if event.mimeData().hasFormat('application/x-dnditemdata'):
itemData = event.mimeData().data('application/x-dnditemdata')
dataStream = QDataStream(itemData, QIODevice.ReadOnly)
pixmap = QPixmap()
offset = QPoint()
dataStream >> pixmap >> offset
newIcon = QLabel(self)
newIcon.setPixmap(pixmap)
newIcon.move(event.pos() - offset)
newIcon.show()
newIcon.setAttribute(Qt.WA_DeleteOnClose)
if newIcon.y()+32 > self.minimumHeight():
self.setMinimumHeight(newIcon.y()+32)
if newIcon.x()+32 > self.minimumWidth():
self.setMinimumWidth(newIcon.x()+32)
if event.source() == self:
event.setDropAction(Qt.MoveAction)
event.accept()
else:
event.acceptProposedAction()
else:
event.ignore()
def mousePressEvent(self, event):
child = self.childAt(event.pos())
if not child:
return
pixmap = QPixmap(child.pixmap())
itemData = QByteArray()
dataStream = QDataStream(itemData, QIODevice.WriteOnly)
dataStream << pixmap << QPoint(event.pos() - child.pos())
mimeData = QMimeData()
mimeData.setData('application/x-dnditemdata', itemData)
drag = QDrag(self)
drag.setMimeData(mimeData)
drag.setPixmap(pixmap)
drag.setHotSpot(event.pos() - child.pos())
tempPixmap = QPixmap(pixmap)
painter = QPainter()
painter.begin(tempPixmap)
painter.fillRect(pixmap.rect(), QColor(127, 127, 127, 127))
painter.end()
child.setPixmap(tempPixmap)
if drag.exec_(Qt.CopyAction | Qt.MoveAction) == Qt.MoveAction:
child.close()
else:
child.show()
child.setPixmap(pixmap)
class Window(QWidget):
def __init__(self, parent=None):
super(Window, self).__init__()
self.pattern = "images/pattern.png"
self.widget = QWidget()
self.palette = QPalette()
self.palette.setBrush(QPalette.Background, QBrush(QPixmap(self.pattern)))
self.widget.setPalette(self.palette)
layout = QVBoxLayout(self)
layout.addWidget(DragWidget())
self.widget.setLayout(layout)
scroll = QScrollArea()
scroll.setVerticalScrollBarPolicy(Qt.ScrollBarAsNeeded)
scroll.setHorizontalScrollBarPolicy(Qt.ScrollBarAsNeeded)
scroll.setWidgetResizable(True)
scroll.setWidget(self.widget)
vlayout = QVBoxLayout(self)
vlayout.setContentsMargins(0, 0, 0, 0)
vlayout.setSpacing(0)
vlayout.addWidget(scroll)
self.setLayout(vlayout)
self.show()
if __name__ == '__main__':
app = QApplication(sys.argv)
window = Window('./')
window2 = Window('./')
sys.exit(app.exec_())
обратите внимание на метод dropEvent() класса DragWidget().
if newIcon.y()+32 > self.minimumHeight():
self.setMinimumHeight(newIcon.y()+32)
if newIcon.x()+32 > self.minimumWidth():
self.setMinimumWidth(newIcon.x()+32)
поэтому, если значок новой позиции больше, чем
The MinimumSize (MinimumWidth и MinimHeight),
затем добавьте смещение к self.minimumSize
спасибо Avaris из канала #pyqt за помощь:)