Pyqt passing parameters to a form based on user action - qt

I have a form and a popup form as given below (partial code):
import sys
import subprocess
import os
from PyQt4 import QtCore, QtGui
from ui_auto import Ui_Form
from popup_ui import Ui_Form as fm
class MyPopupForm(QtGui.QWidget):
def __init__(self, parent=None):
QtGui.QWidget.__init__(self, parent)
self.ui = fm()
self.ui.setupUi(self)
class MyForm(QtGui.QMainWindow):
def __init__(self, parent=None):
QtGui.QWidget.__init__(self, parent)
self.ui = Ui_Form()
self.ui.setupUi(self)
def when_pressed(self):
self.mypopup=MyPopupForm()
self.mypopup.show()
def when_stopped(self):
self.mypopup=MyPopupForm()
self.mypopup.show()
Myform is my main form and MyPopupForm is the popup form. I need to do in such a way that, when I press a button it will print some string and display that string. When I press another button i have to invoke the same form but with different string. How could I do that (I used Qtdesigner to create UI)
MyPopupForm code in python:
# -*- coding: utf-8 -*-
# Form implementation generated from reading ui file 'popup.ui'
#
# Created: Sun Jan 8 11:18:43 2012
# by: PyQt4 UI code generator 4.7.3
#
# WARNING! All changes made in this file will be lost!
from PyQt4 import QtCore, QtGui
class Ui_Form(object):
def setupUi(self, Form):
Form.setObjectName("Form")
Form.resize(207, 170)
self.pushButton = QtGui.QPushButton(Form)
self.pushButton.setGeometry(QtCore.QRect(60, 120, 92, 27))
self.pushButton.setObjectName("pushButton")
self.label = QtGui.QLabel(Form)
self.label.setGeometry(QtCore.QRect(58, 30, 81, 41))
#self.label.setText("")
self.label.setObjectName("label")
self.retranslateUi(Form)
QtCore.QObject.connect(self.pushButton, QtCore.SIGNAL("clicked()"), Form.close)
QtCore.QMetaObject.connectSlotsByName(Form)
def retranslateUi(self, Form):
Form.setWindowTitle(QtGui.QApplication.translate("Form", "Form", None, QtGui.QApplication.UnicodeUTF8))
self.pushButton.setText(QtGui.QApplication.translate("Form", "OK", None, QtGui.QApplication.UnicodeUTF8))

The simplest way is to add a parameter to the __init__ method of the class MyPopupForm
def __init__(self, string_to_be_passed=None, parent=None):
and then when you call it with
self.mypopup=MyPopupForm("value_to_display")
using the string_to_be_passed in the __init__ method to display the value.
Another method is to add a method to the class MyPopupForm to set the string to display and then
self.mypopup=MyPopupForm()
self.mypopup.setValueToDisplay("value")
self.mypopup.show()
with the setValueToDisplay() that display the string where needed.

When compiling the python module with pyuic4, I think it is best to use the -w option, which will create a much simpler ui class without all the setupUi nonsense.
Doing it that way also means the class has exactly the name you gave it in Designer (rather than the nasty mangled version with the Ui_ prefix), and it's also much simpler to subclass it if you need to.
Below, I've included a ui file with a simple Dialog class for showing a message. There's also a script that demonstrates how to use it.
Save the ui file as dialog.ui, and do:
pyuic4 -w dialog.ui > dialog.py
to compile the python module. Then run the script from the same directory.
UI File:
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>Dialog</class>
<widget class="QDialog" name="Dialog">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>400</width>
<height>125</height>
</rect>
</property>
<property name="windowTitle">
<string>Dialog</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QLabel" name="labelMessage">
<property name="frameShape">
<enum>QFrame::StyledPanel</enum>
</property>
<property name="text">
<string/>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="buttonClose">
<property name="text">
<string>Close</string>
</property>
</widget>
</item>
</layout>
</widget>
<resources/>
<connections>
<connection>
<sender>buttonClose</sender>
<signal>clicked()</signal>
<receiver>Dialog</receiver>
<slot>reject()</slot>
<hints>
<hint type="sourcelabel">
<x>194</x>
<y>107</y>
</hint>
<hint type="destinationlabel">
<x>402</x>
<y>88</y>
</hint>
</hints>
</connection>
</connections>
</ui>
Script:
from PyQt4 import QtGui, QtCore
from dialog import Dialog
class Window(QtGui.QWidget):
def __init__(self):
QtGui.QWidget.__init__(self)
self.buttonOne = QtGui.QPushButton('Test One', self)
self.buttonOne.clicked.connect(self.handleButtonOne)
self.buttonTwo = QtGui.QPushButton('Test Two', self)
self.buttonTwo.clicked.connect(self.handleButtonTwo)
layout = QtGui.QHBoxLayout(self)
layout.addWidget(self.buttonOne)
layout.addWidget(self.buttonTwo)
def showDialog(self, message):
dialog = Dialog(self)
dialog.setAttribute(QtCore.Qt.WA_DeleteOnClose)
dialog.labelMessage.setText(message)
dialog.show()
def handleButtonOne(self):
self.showDialog('This is the message for Button One')
def handleButtonTwo(self):
self.showDialog('This is the message for Button Two')
if __name__ == '__main__':
import sys
app = QtGui.QApplication(sys.argv)
window = Window()
window.show()
sys.exit(app.exec_())

Related

pyqtgraph plot not filling whole widget (from qt designer)

I'm trying to embed a pyqtgraph plot in my PySide6 app but the plot is not filling the whole widget:
I want the whole PlotWidget to be filled. The PlotWidget got created with QT-Designer.
The App:
import sys
from PySide6.QtUiTools import QUiLoader
from PySide6.QtWidgets import QApplication, QMainWindow
import pyqtgraph
class MainWindow(QMainWindow):
def __init__(self):
super().__init__()
self.window = QUiLoader().load("test.ui", self)
self.plot_widget = pyqtgraph.PlotWidget(parent=self.window.graphicsView)
self.plot_widget.plot([1, 2, 3], [1, 2, 3])
self.window.show()
if __name__ == "__main__":
App = QApplication(sys.argv)
MW = MainWindow()
sys.exit(App.exec())
The test.ui file:
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>MainWindow</class>
<widget class="QMainWindow" name="MainWindow">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>800</width>
<height>600</height>
</rect>
</property>
<property name="windowTitle">
<string>MainWindow</string>
</property>
<widget class="QWidget" name="centralwidget">
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="PlotWidget" name="graphicsView"/>
</item>
</layout>
</widget>
<widget class="QMenuBar" name="menubar">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>800</width>
<height>22</height>
</rect>
</property>
</widget>
<widget class="QStatusBar" name="statusbar"/>
</widget>
<customwidgets>
<customwidget>
<class>PlotWidget</class>
<extends>QGraphicsView</extends>
<header>pyqtgraph</header>
</customwidget>
</customwidgets>
<resources/>
<connections/>
</ui>
So how can I make the plot fill the whole widget?
There is no need for the UI file.
You will get the desired result by simply creating the plotWidget and setting it as the centralWidget for the mainWindow.
import sys
from PySide6.QtUiTools import QUiLoader
from PySide6.QtWidgets import QApplication, QMainWindow
import pyqtgraph
class MainWindow(QMainWindow):
def __init__(self):
super().__init__()
self.plot_widget = pyqtgraph.PlotWidget()
self.plot_widget.plot([1, 2, 3], [1, 2, 3])
self.setCentralWidget(self.plot_widget)
if __name__ == "__main__":
App = QApplication(sys.argv)
MW = MainWindow()
MW.show()
sys.exit(App.exec())
I am not very familiar with using UI files with pyqtgraph, but it appears to me that the UI file is automatically generating a QGraphicsView right were you want to put your PlotWidget. So one way of making it work would be to deleting the QGraphicsView and replacing it in the layout with your PlotWidget.
import sys
from PySide6.QtUiTools import QUiLoader
from PySide6.QtWidgets import QApplication, QMainWindow
import pyqtgraph
class WindowUi:
def __init__(self):
self.window = QUiLoader().load("test.ui")
layout = self.window.verticalLayout
item = layout.takeAt(0)
item.widget().deleteLater()
self.plot_widget = pyqtgraph.PlotWidget(parent=self.window.graphicsView)
layout.addWidget(self.plot_widget)
self.plot_widget.plot([1, 2, 3], [1, 2, 3])
self.window.show()
if __name__ == "__main__":
App = QApplication(sys.argv)
MW = WindowUi()
sys.exit(App.exec())

How to Fix QStatusBar that stops to work if placed it in Layout?

I succeeded to moved the QStatusBar to a specific location (repositioning), but when I hover I don't see the tips anymore. I tried QStatusBar.show() or .setVisible(True) but doesn't still work. How would you approach this. Thanks
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<widget name="__qt_fake_top_level">
<widget class="QPushButton" name="greetBTN">
<property name="geometry">
<rect>
<x>70</x>
<y>10</y>
<width>75</width>
<height>24</height>
</rect>
</property>
<property name="statusTip">
<string>Greeting people,...</string>
</property>
<property name="text">
<string>greet</string>
</property>
</widget>
<widget class="QWidget" name="gridLayoutWidget">
<property name="geometry">
<rect>
<x>30</x>
<y>40</y>
<width>241</width>
<height>80</height>
</rect>
</property>
<layout class="QGridLayout" name="gridLayout_status"/>
</widget>
<widget class="QPushButton" name="closeBTN">
<property name="geometry">
<rect>
<x>160</x>
<y>10</y>
<width>75</width>
<height>24</height>
</rect>
</property>
<property name="statusTip">
<string>About to close</string>
</property>
<property name="text">
<string>close</string>
</property>
</widget>
</widget>
<resources/>
</ui>
converted to Python
# -*- coding: utf-8 -*-
from PySide5.QtCore import *
from PySide5.QtGui import *
from PySide5.QtWidgets import *
class Ui_AppMainWindow(object):
def setupUi(self, AppMainWindow):
if not AppMainWindow.objectName():
AppMainWindow.setObjectName(u"AppMainWindow")
AppMainWindow.resize(303, 190)
self.centralwidget = QWidget(AppMainWindow)
self.centralwidget.setObjectName(u"centralwidget")
self.greetBTN = QPushButton(self.centralwidget)
self.greetBTN.setObjectName(u"greetBTN")
self.greetBTN.setGeometry(QRect(70, 10, 75, 24))
self.closeBTN = QPushButton(self.centralwidget)
self.closeBTN.setObjectName(u"closeBTN")
self.closeBTN.setGeometry(QRect(160, 10, 75, 24))
self.gridLayoutWidget = QWidget(self.centralwidget)
self.gridLayoutWidget.setObjectName(u"gridLayoutWidget")
self.gridLayoutWidget.setGeometry(QRect(30, 40, 241, 80))
self.gridLayout_status = QGridLayout(self.gridLayoutWidget)
self.gridLayout_status.setObjectName(u"gridLayout_status")
self.gridLayout_status.setContentsMargins(0, 0, 0, 0)
AppMainWindow.setCentralWidget(self.centralwidget)
self.statusbar = QStatusBar(AppMainWindow)
self.statusbar.setObjectName(u"statusbar")
AppMainWindow.setStatusBar(self.statusbar)
self.retranslateUi(AppMainWindow)
QMetaObject.connectSlotsByName(AppMainWindow)
# setupUi
def retranslateUi(self, AppMainWindow):
AppMainWindow.setWindowTitle(QCoreApplication.translate("AppMainWindow", u"MainWindow", None))
#if QT_CONFIG(statustip)
self.greetBTN.setStatusTip(QCoreApplication.translate("AppMainWindow", u"Greeting people,...", None))
#endif // QT_CONFIG(statustip)
self.greetBTN.setText(QCoreApplication.translate("AppMainWindow", u"greet", None))
#if QT_CONFIG(statustip)
self.closeBTN.setStatusTip(QCoreApplication.translate("AppMainWindow", u"About to close", None))
#endif // QT_CONFIG(statustip)
self.closeBTN.setText(QCoreApplication.translate("AppMainWindow", u"close", None))
# retranslateUi
from PyQt5 import QtWidgets, uic
from PyQt5.QtWidgets import *
import sys
from PySide6.QtCore import *
from PySide6.QtGui import *
from PySide6.QtWidgets import *
class Ui(QtWidgets.QMainWindow):
def __init__(self):
super(Ui, self).__init__()
uic.loadUi('Xuntitled.ui', self)
self.statusbar.setVisible(True)
self.statusbar.setStyleSheet('Background:red;')
self.statusbar.setParent(self)
#self.statusbar.showMessage('sqddsfdsfd') # works but if I hover, nothing !
self.statusbar.move(50, 25)
self.gridLayout_status.addWidget(self.statusbar, 1, 1)
self.show()
app = QtWidgets.QApplication(sys.argv)
window = Ui()
app.exec_()
The expected behavior of a status bar is to be shown on the bottom margin of the window, allowing temporary messages and also providing an internal layout for "extra widgets" displayed in it.
If you want to show the status tip somewhere else, then you probably don't need a QStatusBar at all, and a basic QLabel will suffice.
The only requirement is to override the event() function of the window and check for StatusTip events.
In the following example I assumed that you don't really need the default status bar (so you should remove it from Designer and update the generated uic file accordingly if you use that approach).
class Ui(QMainWindow):
def __init__(self):
super(Ui, self).__init__()
uic.loadUi('Xuntitled.ui', self)
self.fakeStatusBar = QLabel()
self.gridLayout_status.addWidget(self.fakeStatusBar)
def event(self, event):
if event.type() == event.StatusTip:
self.fakeStatusBar.setText(event.tip())
return True
return super().event(event)

resize QMainWindow according to contents

I send the whole code of my small application (it needs ZeroTier-One installed to be run).
QMainWindow centralWidget contains essentially a QTableView (inside a QGroupBox).
My aim is to resize the whole QMainWindow to fit contents snugly.
This code seems to work correctly vertically (almost correctly: I didn't find a way to shrink table beyond a certain limit), but horizontally cuts table roughly in half.
This is what I get:
... and this is what I would like to have:
(getting rid of blank space at the bottom would be even better, but I suspect this would be another, possibly unrelated, question)
I already perused several answers including: Resize window to fit content and Resize QMainWindow to minimal size after content of layout changes
What am I missing?
import json
import os
import sys
import typing
from PyQt6.QtCore import Qt, QAbstractTableModel, pyqtSlot, QModelIndex, QSettings, QTimer
from PyQt6.QtWidgets import QApplication, QMainWindow, QInputDialog, QHeaderView
from PyQt6.uic import loadUi
from urllib3 import PoolManager
class NetworksModel(QAbstractTableModel):
class Column:
def __init__(self, tag, header):
self.tag = tag
self.header = header
def data(self, item, role):
if role == Qt.ItemDataRole.DisplayRole:
return str(item[self.tag])
class CBColumn(Column):
def data(self, item, role):
if role == Qt.ItemDataRole.CheckStateRole:
return Qt.CheckState.Checked if item[self.tag] else Qt.CheckState
class LiColumn(Column):
def data(self, item, role):
if role == Qt.ItemDataRole.DisplayRole:
return '\n'.join(item[self.tag])
columns = [
Column('name', 'Name'),
Column('id', 'NwID'),
Column('status', 'Status'),
Column('type', 'Type'),
LiColumn('assignedAddresses', 'Addresses'),
CBColumn('allowDNS', 'DNS')
]
def __init__(self):
super().__init__()
self._data = []
def data(self, index: QModelIndex, role: int = ...) -> typing.Any:
r = index.row()
c = index.column()
if r < len(self._data):
e: dict = self._data[r]
return self.columns[c].data(e, role)
def rowCount(self, parent: QModelIndex = ...) -> int:
return len(self._data)
def columnCount(self, parent: QModelIndex = ...) -> int:
return len(self.columns)
def headerData(self, section: int, orientation: Qt.Orientation, role: int = ...) -> typing.Any:
if role == Qt.ItemDataRole.DisplayRole:
if orientation == Qt.Orientation.Horizontal:
return self.columns[section].header
def set(self, data):
self.beginResetModel()
self._data = data
self.endResetModel()
def flags(self, index: QModelIndex) -> Qt.ItemFlag:
f = super().flags(index)
# c = index.column()
# i = self.columns[c]
# if i['formatter'] == bool:
# f |= Qt.ItemFlag.ItemIsUserCheckable
return f
class MainWindow(QMainWindow):
def __init__(self, settings):
super().__init__()
loadUi("mainwindow.ui", self)
self.settings: QSettings = settings
self.authtoken = self.settings.value('local/authtoken', None)
self.pm = PoolManager()
self.model = NetworksModel()
self.networks.horizontalHeader().setSectionResizeMode(QHeaderView.ResizeMode.ResizeToContents)
self.networks.verticalHeader().setSectionResizeMode(QHeaderView.ResizeMode.ResizeToContents)
self.networks.setModel(self.model)
self.refresh_timer = QTimer()
self.refresh_timer.timeout.connect(self.on_actionrefresh_triggered)
if self.authtoken:
self.refresh_timer.start(5*1000)
self.on_actionrefresh_triggered()
# self.main_layout.setSizeConstraint(QLayout.SizeConstraint.SetFixedSize)
#pyqtSlot()
def on_actionauthtoken_triggered(self):
authtoken, ok = QInputDialog.getText(self, 'enter authtoken', '24 alphanumerics')
if ok:
self.authtoken = authtoken
# TODO: enable refreshing
self.settings.setValue('local/authtoken', authtoken)
self.settings.sync()
self.on_actionrefresh_triggered()
self.refresh_timer.start(5*1000)
#pyqtSlot()
def on_actionrefresh_triggered(self):
if self.authtoken:
r = self.pm.request('GET', 'http://localhost:9993/network', headers={'X-ZT1-AUTH': self.authtoken})
if r.status == 200:
j = r.data
li = json.loads(j)
self.model.set(li)
self.trigger_resize()
else:
print(f'on_actionrefresh_triggered() request ERROR: {r.status}')
self.refresh_timer.stop()
else:
print('on_actionrefresh_triggered() ERROR: missing authtoken')
self.refresh_timer.stop()
def trigger_resize(self):
def _resize_me():
self.adjustSize()
# self.resize(self.minimumSizeHint())
QTimer.singleShot(10, _resize_me)
if __name__ == '__main__':
os.environ['DISPLAY'] = "localhost:10.0"
app = QApplication(sys.argv)
window = MainWindow(QSettings('Condarelli', 'ZT1'))
window.show()
# Start the event loop.
exit(app.exec())
and mainwindow.ui:
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>MainWindow</class>
<widget class="QMainWindow" name="MainWindow">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>800</width>
<height>600</height>
</rect>
</property>
<property name="windowTitle">
<string>MainWindow</string>
</property>
<widget class="QWidget" name="centralwidget">
<layout class="QVBoxLayout" name="main_layout">
<item>
<widget class="QGroupBox" name="groupBox">
<property name="sizePolicy">
<sizepolicy hsizetype="MinimumExpanding" vsizetype="MinimumExpanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="title">
<string>Networks:</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_2">
<item>
<widget class="QTableView" name="networks">
<property name="sizePolicy">
<sizepolicy hsizetype="MinimumExpanding" vsizetype="MinimumExpanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
</widget>
</item>
</layout>
</widget>
</item>
</layout>
</widget>
<widget class="QMenuBar" name="menubar">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>800</width>
<height>20</height>
</rect>
</property>
<widget class="QMenu" name="menuFile">
<property name="title">
<string>File</string>
</property>
<addaction name="actionauthtoken"/>
<addaction name="actionrefresh"/>
</widget>
<addaction name="menuFile"/>
</widget>
<widget class="QStatusBar" name="statusbar"/>
<action name="actionauthtoken">
<property name="text">
<string>authtoken</string>
</property>
<property name="toolTip">
<string>set authtoken</string>
</property>
</action>
<action name="actionrefresh">
<property name="text">
<string>refresh</string>
</property>
</action>
</widget>
<resources/>
<connections/>
</ui>

A QWidget in a QLayout is shifted and cut when window is maximized

There is a simple GUI: main window with a default central widget. A layout is added to it and then a widget of interest is placed to the layout.
import sys
from matplotlib.backends.backend_qt5agg import FigureCanvas
from matplotlib.figure import Figure
from PyQt5 import QtWidgets
from PyQt5.QtCore import Qt
from PyQt5.uic import loadUiType
FormClass, QtBaseClass = loadUiType('main_window.ui')
class MainWindow(FormClass, QtBaseClass):
def __init__(self):
super(MainWindow, self).__init__()
self.setupUi(self)
self.fig = Figure(facecolor='yellow', edgecolor='red', linewidth=0.1)
self.canvas = FigureCanvas(self.fig)
hbox_layout = QtWidgets.QHBoxLayout(self.centralwidget)
hbox_layout.addWidget(self.canvas, stretch=2)
app = QtWidgets.QApplication(sys.argv)
main_window = MainWindow()
main_window.show()
sys.exit(app.exec_())
main_window.ui:
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>MainWindow</class>
<widget class="QMainWindow" name="MainWindow">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>1024</width>
<height>768</height>
</rect>
</property>
<property name="windowTitle">
<string>MainWindow</string>
</property>
<widget class="QWidget" name="centralwidget"/>
<widget class="QMenuBar" name="menubar">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>1024</width>
<height>21</height>
</rect>
</property>
</widget>
<widget class="QStatusBar" name="statusbar"/>
</widget>
<resources/>
<connections/>
</ui>
When the main window is not maximized, everything seems good:
The whole widget is visible (notice a red border, it was added to monitor the edges of the widget).
But if we maximize the main window, this is what happens:
Looks like the widget is shifted upwards, the top border of the widget disappears, while at the bottom a black line appears under the edge.
I've tested it with HBox/VBox/Grid layouts, the result is always the same. This happens if there is only one widget in a column. If we add one more widget to the column, both widgets will be fully visible.
Why does it happen and how to fix this behavior? Are we not supposed to have a single widget in a column inside a layout?
OS: Windows 10
Qt: 5.6.2
PyQt: 5.6.0
I just checked it by creating a new Qt Widgets Application and the issue is not present. To paint the widget I use Qt Style Sheets as follow:
QWidget {
border: 1px solid red;
background-color: yellow;
}
When the application runs it shows well even maximized (see bellow). Re-evaluate the method you use to paint the widget. You can change Style Sheets by using the Style Sheet property in the designer.
See also: Qt Style Sheets Syntax.

qt+pyqt emitted dropped URL twice

I've used QT-Designer to create a xml-File, which contains a LineEdit widget. In the script i've tried to emit the file-path via drag-drop. It works but st. is wrong: the url will be emitted twice and looks like:
/D:/Qtfile:///D:/Qt
i know similar topics like PyQt event emmitted twice are discussed in stackoverflow. but i cannot find my answer...maybe i miss it. Why twice? Why the first "file://" disappeared?
If i dont use Qt-Designer and define a SubClass for drag-drop a text like class CustomEditLine(QLineEdit):... and then make the instance of QlineEdit in the main-Window, url will be emitted only once but still "/D:/Qt".
here is my code:
from PyQt5 import QtWidgets, uic
from PyQt5.QtCore import QObject,QEvent
import sys
qtCreatorFile=".\\gui\\testdrop.ui"
Ui_MainWindow, QtBaseClass = uic.loadUiType(qtCreatorFile)
class QDropHandler(QObject):
def __init__(self, parent=None):
super(QDropHandler, self).__init__(parent)
def eventFilter(self, obj, event):
if event.type() == QEvent.DragEnter:
event.accept()
if event.type() == QEvent.Drop:
md = event.mimeData()
if md.hasUrls():
for url in md.urls():
obj.setText(url.path())
break
event.accept()
return False
class root_App(QtWidgets.QMainWindow, Ui_MainWindow):
def __init__(self):
super(root_App, self).__init__()
self.setupUi(self)
self.lineEdit_1.installEventFilter(QDropHandler(self))
if __name__=="__main__":
app= QtWidgets.QApplication(sys.argv)
window=root_App()
window.show()
sys.exit(app.exec_())
and my ui-xml:
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>Form</class>
<widget class="QWidget" name="Form">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>758</width>
<height>424</height>
</rect>
</property>
<property name="acceptDrops">
<bool>true</bool>
</property>
<property name="windowTitle">
<string>Form</string>
</property>
<widget class="QLineEdit" name="lineEdit_1">
<property name="geometry">
<rect>
<x>40</x>
<y>140</y>
<width>691</width>
<height>20</height>
</rect>
</property>
</widget>
</widget>
<resources/>
<connections/>
</ui>
The QLineEdit class already supports dragging and dropping urls. Your custom handler doesn't fully override that, so that explains why the text is being entered twice. To fully override the default behaviour, your event-filter must return True - meaning: yes, I've dealt with this event, so there's nothing more to do.
Your example code can be simplified to this:
class root_App(QtWidgets.QMainWindow, Ui_MainWindow):
def __init__(self):
super(root_App, self).__init__()
self.setupUi(self)
self.lineEdit_1.installEventFilter(self)
def eventFilter(self, source, event):
if (event.type() == QEvent.Drop and
source is self.lineEdit_1):
md = event.mimeData()
if md.hasUrls():
source.setText(md.urls()[0].path())
return True
return super(root_App, self).eventFilter(source, event)

Resources