pyqt adding a widget to a QListWidget - pyqt

hi i created 2 files from qtdesigner and i created a new file with a class where i want to use these UIs that i created.
this is the file creating the QListWidget
from PyQt4 import QtCore, QtGui
try:
_fromUtf8 = QtCore.QString.fromUtf8
except AttributeError:
_fromUtf8 = lambda s: s
class Ui_main_Dialog_lists(object):
def setupUi(self, main_Dialog_lists):
main_Dialog_lists.setObjectName(_fromUtf8("main_Dialog_lists"))
main_Dialog_lists.resize(590, 521)
self.main_verticalLayout = QtGui.QVBoxLayout(main_Dialog_lists)
self.main_verticalLayout.setObjectName(_fromUtf8("main_verticalLayout"))
self.horizontalLayout = QtGui.QHBoxLayout()
self.horizontalLayout.setObjectName(_fromUtf8("horizontalLayout"))
self.listWidget_nodes = QtGui.QListWidget(main_Dialog_lists)
self.listWidget_nodes.setObjectName(_fromUtf8("listWidget_nodes"))
self.horizontalLayout.addWidget(self.listWidget_nodes)
self.label_arrow = QtGui.QLabel(main_Dialog_lists)
self.label_arrow.setObjectName(_fromUtf8("label_arrow"))
self.horizontalLayout.addWidget(self.label_arrow)
self.listWidget_nodes_to_render = QtGui.QListWidget(main_Dialog_lists)
self.listWidget_nodes_to_render.setObjectName(_fromUtf8("listWidget_nodes_to_render"))
self.horizontalLayout.addWidget(self.listWidget_nodes_to_render)
self.main_verticalLayout.addLayout(self.horizontalLayout)
self.retranslateUi(main_Dialog_lists)
QtCore.QMetaObject.connectSlotsByName(main_Dialog_lists)
def retranslateUi(self, main_Dialog_lists):
main_Dialog_lists.setWindowTitle(QtGui.QApplication.translate("main_Dialog_lists", "Dialog", None, QtGui.QApplication.UnicodeUTF8))
self.label_arrow.setText(QtGui.QApplication.translate("main_Dialog_lists", ">", None, QtGui.QApplication.UnicodeUTF8))
this is the class creating the widget i want to insert into the rows of the QListWidget
from PyQt4 import QtCore, QtGui
try:
_fromUtf8 = QtCore.QString.fromUtf8
except AttributeError:
_fromUtf8 = lambda s: s
class Ui_Frame_nodes(object):
def setupUi(self, Frame_nodes):
Frame_nodes.setObjectName(_fromUtf8("Frame_nodes"))
Frame_nodes.resize(508, 128)
Frame_nodes.setFrameShape(QtGui.QFrame.StyledPanel)
Frame_nodes.setFrameShadow(QtGui.QFrame.Raised)
self.verticalLayout_2 = QtGui.QVBoxLayout(Frame_nodes)
self.verticalLayout_2.setObjectName(_fromUtf8("verticalLayout_2"))
self.horizontalLayout_names = QtGui.QHBoxLayout()
self.horizontalLayout_names.setObjectName(_fromUtf8("horizontalLayout_names"))
self.label_node = QtGui.QLabel(Frame_nodes)
self.label_node.setObjectName(_fromUtf8("label_node"))
self.horizontalLayout_names.addWidget(self.label_node)
self.label_name_start = QtGui.QLabel(Frame_nodes)
self.label_name_start.setObjectName(_fromUtf8("label_name_start"))
self.horizontalLayout_names.addWidget(self.label_name_start)
self.label_name_end = QtGui.QLabel(Frame_nodes)
self.label_name_end.setObjectName(_fromUtf8("label_name_end"))
self.horizontalLayout_names.addWidget(self.label_name_end)
self.label_name_inter = QtGui.QLabel(Frame_nodes)
self.label_name_inter.setObjectName(_fromUtf8("label_name_inter"))
self.horizontalLayout_names.addWidget(self.label_name_inter)
self.verticalLayout_2.addLayout(self.horizontalLayout_names)
self.horizontalLayout_Inputs = QtGui.QHBoxLayout()
self.horizontalLayout_Inputs.setObjectName(_fromUtf8("horizontalLayout_Inputs"))
self.label_node_name = QtGui.QLabel(Frame_nodes)
self.label_node_name.setObjectName(_fromUtf8("label_node_name"))
self.horizontalLayout_Inputs.addWidget(self.label_node_name)
self.lineEdit_node_start = QtGui.QLineEdit(Frame_nodes)
self.lineEdit_node_start.setObjectName(_fromUtf8("lineEdit_node_start"))
self.horizontalLayout_Inputs.addWidget(self.lineEdit_node_start)
self.lineEdit = QtGui.QLineEdit(Frame_nodes)
self.lineEdit.setObjectName(_fromUtf8("lineEdit"))
self.horizontalLayout_Inputs.addWidget(self.lineEdit)
self.lineEdit_3 = QtGui.QLineEdit(Frame_nodes)
self.lineEdit_3.setObjectName(_fromUtf8("lineEdit_3"))
self.horizontalLayout_Inputs.addWidget(self.lineEdit_3)
self.verticalLayout_2.addLayout(self.horizontalLayout_Inputs)
self.retranslateUi(Frame_nodes)
QtCore.QMetaObject.connectSlotsByName(Frame_nodes)
def retranslateUi(self, Frame_nodes):
Frame_nodes.setWindowTitle(QtGui.QApplication.translate("Frame_nodes", "Frame", None, QtGui.QApplication.UnicodeUTF8))
self.label_node.setText(QtGui.QApplication.translate("Frame_nodes", "Node", None, QtGui.QApplication.UnicodeUTF8))
self.label_name_start.setText(QtGui.QApplication.translate("Frame_nodes", "Start", None, QtGui.QApplication.UnicodeUTF8))
self.label_name_end.setText(QtGui.QApplication.translate("Frame_nodes", "End", None, QtGui.QApplication.UnicodeUTF8))
self.label_name_inter.setText(QtGui.QApplication.translate("Frame_nodes", "Inter", None, QtGui.QApplication.UnicodeUTF8))
self.label_node_name.setText(QtGui.QApplication.translate("Frame_nodes", "Node Name", None, QtGui.QApplication.UnicodeUTF8))
after compiling the 2 .ui files i created this file and i am trying to use them, so i can put one inside the other.
import lists
import nodes
from PyQt4 import QtCore, QtGui
import sys
class Master(QtGui.QFrame, QtGui.QWidget, nodes.Ui_Frame_nodes):
def __init__(self):
QtGui.QWidget.__init__(self)
QtGui.QFrame.__init__(self)
self.ui = lists.Ui_main_Dialog_lists()
self.ui.setupUi(self)
for i in range(2):
item_widget = nodes.Ui_Frame_nodes()
qframe = QtGui.QFrame()
item_widget.setupUi(qframe)
wid2 = QtGui.QListWidgetItem()
self.ui.listWidget_nodes.addItem(wid2)
#here is where the script doesnt like it
self.ui.listWidget_nodes.setItemWidget(wid2, item_widget)
app = QtGui.QApplication(sys.argv)
m = Master()
m.show()
app.exec_()
but i cant make it on the setItemWidget i get an error saying
TypeError: QListWidget.setItemWidget(QListWidgetItem, QWidget): argument 2 has unexpected type 'Ui_Frame_nodes'
this is my first time trying to put a widget inside another i am not sure if i am doing it properly.
thanks guys
and here is an image of the UIs
https://dl.dropboxusercontent.com/u/14346803/ui_qt_designer.png

Your problem might be that you haven't setup nodes correctly. I think what's happening is its trying to initialise as a python object (not Qt). I can't currently test this.
You probably need something like:
class CustomNodes(QWidget):
def __init__(self, parent=None):
super(CustomNodes, self).__init__(parent)
self.ui = nodes.Ui_Frame_nodes()
self.ui.setupUi(self)
Then use:
item_widget = CustomNodes(qframe)
self.ui.listWidget_nodes.setItemWidget(wid2, item_widget)
Please note: I haven't tested this code.

Related

How to use QtWebEngine createWindow in PyQt5

I am trying to make a window that contains a QWebEngineView. Now I want the browser to be able to handle the create window or _blank type triggers, or specifically to open a URL in a new window when required. In the below code, when there is requirement to create a window by the browser, createwindow() is called, but that doesn't open the window. Please help me with the correct way to open a new window by the browser when required in the below case.
import json
import sys
import os
import time
import json
import sys
import platform
from PyQt5 import QtCore, QtGui, QtWidgets
from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *
from PyQt5.QtWebEngineWidgets import QWebEngineView, QWebEnginePage
from PyQt5.QtWebEngineWidgets import QWebEngineSettings as QWebSettings
from PyQt5.QtGui import QDesktopServices
from PyQt5.QtCore import QUrl
from main_dash import Ui_MainWindow
class MainDashWindow(QMainWindow):
socketSignal = QtCore.pyqtSignal(object) # must be defined in class level
def __init__(self):
QMainWindow.__init__(self)
self.ui = Ui_MainWindow()
# self.ui.setupUi(self)
# ui = Ui_MainWindow()
self.isMax = 0
self.ui.setupUi(self)
def re_setup(self):
self.page = WebEnginePage2()
self.page.Notifications = True
self.ui.full_content_container.hide()
self.page.createWindow = True
self.page.settings().setAttribute(QWebSettings.JavascriptEnabled, True)
self.page.settings().setAttribute(QWebSettings.JavascriptCanOpenWindows, True)
self.page.settings().setAttribute(
QWebSettings.JavascriptCanAccessClipboard, True)
# self.full_content_container is the webengineview in the mainUi file
self.ui.full_content_container.setPage(self.page)
# self.ui.full_content_container.setContextMenuPolicy(Qt.NoContextMenu)
url6 = "...../icons_nec/ui/index.html"
self.ui.full_content_container.setUrl(QtCore.QUrl(url6))
self.ui.full_content_container.loadFinished.connect(
self.on_load_finished)
########################################################################
self.show()
## ==> END ##
def get_path(self, filename):
if hasattr(sys, "_MEIPASS"):
return f'{os.path.join(sys._MEIPASS, filename)}'
else:
return f'{filename}'
def on_load_finished(self):
self.ui.full_content_container.show()
class WebEnginePage2(QWebEnginePage):
def __init__(self, *args, **kwargs):
QWebEnginePage.__init__(self, *args, **kwargs)
self.featurePermissionRequested.connect(
self.onFeaturePermissionRequested)
def onFeaturePermissionRequested(self, url, feature):
self.setFeaturePermission(
url, feature, QWebEnginePage.PermissionGrantedByUser)
def createWindow(self,
wintype: QWebEnginePage.WebWindowType) -> QWebEngineView:
"""Called by Qt when a page wants to create a new tab or window.
In case the user wants to open a resource in a new tab, we use the
createWindow handling of the main page to achieve that.
See WebEngineView.createWindow for details.
"""
return self.page().inspectedPage().view().createWindow(wintype)
# Store external windows.
external_windows = []
def acceptNavigationRequest(self, url, _type, isMainFrame):
print("in navigation")
if _type == QWebEnginePage.NavigationTypeLinkClicked:
w = QWebEngineView()
w.setUrl(url)
w.show()
print("link detected")
# Keep reference to external window, so it isn't cleared up.
self.external_windows.append(w)
return False
# QDesktopServices.openUrl(url)
# elif _type == QWebEnginePage.NavigationType
return super().acceptNavigationRequest(url, _type, isMainFrame)
if __name__ == "__main__":
app = QApplication(sys.argv)
window = MainDashWindow()
window.re_setup()
sys.exit(app.exec_())
Here is the Ui_MainWindow file, which is being imported above.
I need to figure out with such a scenario how can I implement createWindow() if required by websites.
from PyQt5 import QtWebEngineWidgets
import all_icons_rc
from PyQt5 import QtCore, QtGui, QtWidgets
class Ui_MainWindow(object):
def setupUi(self, MainWindow):
MainWindow.setObjectName("MainWindow")
MainWindow.resize(1280, 720)
MainWindow.setMinimumSize(QtCore.QSize(1280, 720))
MainWindow.setMaximumSize(QtCore.QSize(1920, 1080))
self.centralwidget = QtWidgets.QWidget(MainWindow)
self.centralwidget.setObjectName("centralwidget")
self.verticalLayout_2 = QtWidgets.QVBoxLayout(self.centralwidget)
self.verticalLayout_2.setContentsMargins(0, 0, 0, 0)
self.verticalLayout_2.setSpacing(0)
self.verticalLayout_2.setObjectName("verticalLayout_2")
self.Header = QtWidgets.QFrame(self.centralwidget)
self.Header.setMinimumSize(QtCore.QSize(0, 40))
self.Header.setMaximumSize(QtCore.QSize(16777215, 50))
self.Header.setStyleSheet("background-color: rgb(33, 37, 41);")
self.Header.setFrameShape(QtWidgets.QFrame.NoFrame)
self.Header.setFrameShadow(QtWidgets.QFrame.Raised)
self.Header.setObjectName("Header")
self.horizontalLayout_4 = QtWidgets.QHBoxLayout(self.Header)
self.horizontalLayout_4.setContentsMargins(0, 0, 0, 0)
self.horizontalLayout_4.setSpacing(0)
self.horizontalLayout_4.setObjectName("horizontalLayout_4")
self.frame_2 = QtWidgets.QFrame(self.Header)
self.frame_2.setStyleSheet("")
self.frame_2.setFrameShape(QtWidgets.QFrame.StyledPanel)
self.frame_2.setFrameShadow(QtWidgets.QFrame.Raised)
self.frame_2.setObjectName("frame_2")
self.horizontalLayout_4.addWidget(self.frame_2)
self.frame = QtWidgets.QFrame(self.Header)
self.frame.setMaximumSize(QtCore.QSize(150, 16777215))
self.frame.setStyleSheet("/*background-color: rgb(85, 255, 0);*/")
self.frame.setFrameShape(QtWidgets.QFrame.StyledPanel)
self.frame.setFrameShadow(QtWidgets.QFrame.Raised)
self.frame.setObjectName("frame")
self.horizontalLayout = QtWidgets.QHBoxLayout(self.frame)
self.horizontalLayout.setSpacing(15)
self.horizontalLayout.setObjectName("horizontalLayout")
self.minimize_btn = QtWidgets.QPushButton(self.frame)
self.minimize_btn.setText("")
icon = QtGui.QIcon()
icon.addPixmap(QtGui.QPixmap(
":/icons/Icons/icons8_macos_minimize_50px.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
self.minimize_btn.setIcon(icon)
self.minimize_btn.setIconSize(QtCore.QSize(30, 30))
self.minimize_btn.setFlat(True)
self.minimize_btn.setObjectName("minimize_btn")
self.horizontalLayout.addWidget(self.minimize_btn)
self.maximize_btn = QtWidgets.QPushButton(self.frame)
self.maximize_btn.setText("")
icon1 = QtGui.QIcon()
icon1.addPixmap(QtGui.QPixmap(
":/icons/Icons/icons8_maximize_window_50px.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
self.maximize_btn.setIcon(icon1)
self.maximize_btn.setIconSize(QtCore.QSize(30, 30))
self.maximize_btn.setFlat(True)
self.maximize_btn.setObjectName("maximize_btn")
self.horizontalLayout.addWidget(self.maximize_btn)
self.close_btn = QtWidgets.QPushButton(self.frame)
self.close_btn.setText("")
icon2 = QtGui.QIcon()
icon2.addPixmap(QtGui.QPixmap(
":/icons/Icons/icons8_Close_50px_2.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
self.close_btn.setIcon(icon2)
self.close_btn.setIconSize(QtCore.QSize(30, 30))
self.close_btn.setFlat(True)
self.close_btn.setObjectName("close_btn")
self.horizontalLayout.addWidget(self.close_btn)
self.horizontalLayout_4.addWidget(self.frame)
self.verticalLayout_2.addWidget(self.Header)
self.body = QtWidgets.QFrame(self.centralwidget)
self.body.setFrameShape(QtWidgets.QFrame.StyledPanel)
self.body.setFrameShadow(QtWidgets.QFrame.Raised)
self.body.setLineWidth(0)
self.body.setObjectName("body")
self.verticalLayout_3 = QtWidgets.QVBoxLayout(self.body)
self.verticalLayout_3.setContentsMargins(0, 0, 0, 0)
self.verticalLayout_3.setSpacing(0)
self.verticalLayout_3.setObjectName("verticalLayout_3")
self.full_content_container = QtWebEngineWidgets.QWebEngineView(
self.body)#<----This is webengineview
self.full_content_container.setStyleSheet("background-color: rgb(85, 255, 255);\n"
"border:none;")
self.full_content_container.setObjectName("full_content_container")
self.verticalLayout_3.addWidget(self.full_content_container)
self.verticalLayout_2.addWidget(self.body)
MainWindow.setCentralWidget(self.centralwidget)
self.retranslateUi(MainWindow)
QtCore.QMetaObject.connectSlotsByName(MainWindow)
def retranslateUi(self, MainWindow):
_translate = QtCore.QCoreApplication.translate
MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow"))
For now, just Ignore the icons.
index.html file snippet which is being loaded in webengineview for testing
<!DOCTYPE html>
<html>
<body>
<h1>The a target attribute</h1>
<p>Open link in a new window or tab: Visit PathOr!</p>
</body>
</html>
UPDATE:
Below is an implementaion based on your example code. Everything should work as expected if you completely replace your WebEnginePage2 class with this one:
class WebEnginePage2(QWebEnginePage):
_windows = {}
#classmethod
def newWindow(cls):
window = QWebEngineView()
window.setObjectName(f'window-{id(window)}')
window.setAttribute(QtCore.Qt.WA_DeleteOnClose, True)
window.destroyed.connect(
lambda window: cls._windows.pop(window.objectName(), None))
window.setPage(cls(window))
cls._windows[window.objectName()] = window
return window
def __init__(self, *args, **kwargs):
QWebEnginePage.__init__(self, *args, **kwargs)
self.featurePermissionRequested.connect(
self.onFeaturePermissionRequested)
self.geometryChangeRequested.connect(self.handleGeometryChange)
def handleGeometryChange(self, rect):
view = self.view()
window = QtGui.QWindow.fromWinId(view.winId())
if window is not None:
rect = rect.marginsRemoved(window.frameMargins())
view.resize(rect.size())
view.show()
def createWindow(self, mode):
window = self.newWindow()
if mode != QtWebEngineWidgets.QWebEnginePage.WebDialog:
window.resize(800, 600)
window.show()
return window.page()
def onFeaturePermissionRequested(self, url, feature):
self.setFeaturePermission(
url, feature, QWebEnginePage.PermissionGrantedByUser)
You need to create a new instance of the browser window and keep a reference to it in a window list. It's also important to ensure the window is given an appropriate size, otherwise it won't be visible. For windows opened with javascript, the geometryChangeRequested signal can be used to set the requested size, otherwise a default should be used.
Below is a simple demo that implements the basic features. Hopefully it should be obvious how to adapt this to your own application:
from PyQt5 import QtCore, QtGui, QtWidgets, QtWebEngineWidgets
class Browser(QtWebEngineWidgets.QWebEngineView):
_windows = set()
#classmethod
def _removeWindow(cls, window):
cls._windows.discard(window)
#classmethod
def newWindow(cls):
window = cls()
cls._windows.add(window)
return window
def __init__(self, parent=None):
super().__init__(parent)
self.setAttribute(QtCore.Qt.WA_DeleteOnClose, True)
self.page().geometryChangeRequested.connect(self.handleGeometryChange)
self.page().titleChanged.connect(self.setWindowTitle)
def closeEvent(self, event):
self._removeWindow(self)
event.accept()
def handleGeometryChange(self, rect):
window = QtGui.QWindow.fromWinId(self.winId())
if window is not None:
rect = rect.marginsRemoved(window.frameMargins())
self.resize(rect.size())
self.setFocus()
self.show()
def createWindow(self, mode):
window = self.newWindow()
if mode != QtWebEngineWidgets.QWebEnginePage.WebDialog:
window.resize(800, 600)
window.show()
return window
html = """
<html><head><title>Test Page</title>
<script type="text/javascript"><!--
var count = 0
var url = 'https://www.google.com'
function newWindow() {
count += 1
window.open(url, 'Test' + count, 'width=640,height=480');
}
--></script>
</head>
<body>
<input type="button" value="New Window" onclick="newWindow()" />
<p>Blank</p>
</body>
</html>"""
if __name__ == '__main__':
import sys
app = QtWidgets.QApplication(sys.argv)
browser = Browser()
browser.setHtml(html)
browser.setGeometry(600, 100, 400, 200)
browser.show()
sys.exit(app.exec_())

Python PyQt5 Terminal Command execution problem on a button click

I'm trying to create an application, that can execute an embedded Terminal command when ever the button is clicked. The actual problem occurs when i click the button and nothing happens.
I have two scripts one has a terminal widget and the other has the main GUI. Any Help, would be highly appreciated.
That's first Script
import sys
from PyQt5 import QtCore, QtWidgets
class EmbTerminal(QtWidgets.QWidget):
def __init__(self, parent=None):
super(EmbTerminal, self).__init__(parent)
self._process = []
self.start_process('urxvt',['-embed', str(int(self.winId())),"-e","tmux"])
def start_process(self,prog,options):
child = QtCore.QProcess(self)
self._process.append(child)
child.start(prog,options)
def run_command(self, command = "ls" ):
program = "tmux"
options = []
options.extend(["send-keys"])
options.extend([command])
options.extend(["Enter"])
self.start_process(program, options)
That's Second Script
from PyQt5 import QtCore, QtGui, QtWidgets
class Ui_Dialog(object):
def setupUi(self, Dialog):
Dialog.setObjectName("Dialog")
Dialog.resize(745, 496)
self.tabWidget = QtWidgets.QTabWidget(Dialog)
self.tabWidget.setGeometry(QtCore.QRect(100, 190, 561, 261))
self.tabWidget.setObjectName("tabWidget")
self.tab = QtWidgets.QWidget()
self.tab.setObjectName("tab")
self.tabWidget.addTab(EmbTerminal(), "Terminal")
self.tab_2 = QtWidgets.QWidget()
self.tab_2.setObjectName("tab_2")
self.tabWidget.addTab(self.tab_2, "")
self.pushButton = QtWidgets.QPushButton(Dialog)
self.pushButton.setGeometry(QtCore.QRect(280, 70, 211, 71))
self.pushButton.setObjectName("pushButton")
self.retranslateUi(Dialog)
QtCore.QMetaObject.connectSlotsByName(Dialog)
self.pushButton.clicked.connect(lambda: EmbTerminal.run_command(EmbTerminal(), "ls"))
def retranslateUi(self, Dialog):
_translate = QtCore.QCoreApplication.translate
Dialog.setWindowTitle(_translate("Dialog", "Dialog"))
self.tabWidget.setTabText(self.tabWidget.indexOf(self.tab), _translate("Dialog", "Tab 1"))
self.tabWidget.setTabText(self.tabWidget.indexOf(self.tab_2), _translate("Dialog", "Tab 2"))
self.pushButton.setText(_translate("Dialog", "ls"))
from terminal5 import EmbTerminal
if __name__ == "__main__":
import sys
app = QtWidgets.QApplication(sys.argv)
Dialog = QtWidgets.QDialog()
ui = Ui_Dialog()
ui.setupUi(Dialog)
Dialog.show()
sys.exit(app.exec_())
You should consider the following:
You should not modify the code generated by Qt Designer (unless you understand its logic)
Do not implement the logic in the class generated by Qt Designer, it is advisable to create a new class that inherits from the appropriate widget and use the other class to fill it.
In your case the problem is that the EmbTerminal() object in lambda: EmbTerminal.run_command(EmbTerminal(), "ls") only exists while the lambda is running, but the lambda runs for a very short time causing the command not to be sent causing the error.
Considering the above, the solution is:
from PyQt5 import QtCore, QtGui, QtWidgets
class Ui_Dialog(object):
def setupUi(self, Dialog):
Dialog.setObjectName("Dialog")
Dialog.resize(745, 496)
self.tabWidget = QtWidgets.QTabWidget(Dialog)
self.tabWidget.setGeometry(QtCore.QRect(100, 190, 561, 261))
self.tabWidget.setObjectName("tabWidget")
self.pushButton = QtWidgets.QPushButton(Dialog)
self.pushButton.setGeometry(QtCore.QRect(280, 70, 211, 71))
self.pushButton.setObjectName("pushButton")
self.retranslateUi(Dialog)
QtCore.QMetaObject.connectSlotsByName(Dialog)
def retranslateUi(self, Dialog):
_translate = QtCore.QCoreApplication.translate
Dialog.setWindowTitle(_translate("Dialog", "Dialog"))
self.pushButton.setText(_translate("Dialog", "ls"))
from terminal5 import EmbTerminal
class Dialog(QtWidgets.QDialog, Ui_Dialog):
def __init__(self, parent=None):
super().__init__(parent)
self.setupUi(self)
self.terminal = EmbTerminal()
self.tabWidget.addTab(self.terminal, "Terminal")
self.pushButton.clicked.connect(self.on_clicked)
#QtCore.pyqtSlot()
def on_clicked(self):
self.terminal.run_command("ls")
if __name__ == "__main__":
import sys
app = QtWidgets.QApplication(sys.argv)
w = Dialog()
w.show()
sys.exit(app.exec_())
On the other hand if you are only going to send commands then it is not necessary to store the QProcess, instead use QProcess: startDetached and make run_command a classmethod:
class EmbTerminal(QtWidgets.QWidget):
# ...
#staticmethod
def run_command(command = "ls" ):
program = "tmux"
options = []
options.extend(["send-keys"])
options.extend([command])
options.extend(["Enter"])
QtCore.QProcess.startDetached(program, options)

PySide2 v5.12 : Creating a FileDialog on a click of a button

I designed a basic UI in the QtDesigner. Now i am trying to pop a simple file dialog on click of a button, below given is my GUI Code :
from PySide2 import QtCore, QtGui, QtWidgets
class Ui_MainWindow(object):
def setupUi(self, MainWindow):
.....
.....
self.input_Image_GraphicsView = QtWidgets.QGraphicsView(self.centralwidget)
self.input_Image_GraphicsView.setGeometry(QtCore.QRect(730, 110, 480, 320))
self.input_Image_GraphicsView.setObjectName("input_Image_GraphicsView")
......
self.output_Image_GraphicsView = QtWidgets.QGraphicsView(self.centralwidget)
self.output_Image_GraphicsView.setGeometry(QtCore.QRect(730, 480, 480, 320))
self.output_Image_GraphicsView.setObjectName("output_Image_GraphicsView")
......
self.file_Select_Btn = QtWidgets.QPushButton(self.centralwidget)
self.file_Select_Btn.setGeometry(QtCore.QRect(1082, 80, 121, 28))
self.file_Select_Btn.setObjectName("file_Select_Btn")
self.file_Select_Btn.clicked.connect(self.selectFile)
.....
.....
def selectFile():
self.path_To_File = QtWidgets.QFileDialog.getOpenFileName(self, QtCore.QObject.tr("Load Image"), QtCore.QObject.tr("~/Desktop/"), QtCore.QObject.tr("Images (*.jpg)"))
print(self.path_To_File)
.....
.....
if __name__ == "__main__":
import sys
app = QtWidgets.QApplication(sys.argv)
MainWindow = QtWidgets.QMainWindow()
ui = Ui_MainWindow()
ui.setupUi(MainWindow)
MainWindow.show()
sys.exit(app.exec_())
This is the error that i get :
TypeError: descriptor 'tr' requires a 'PySide2.QtCore.QObject' object but received a 'str'
When i wasnt using the 'tr', I was getting :
TypeError: 'PySide2.QtWidgets.QFileDialog.getOpenFileName' called with wrong
argument types:
PySide2.QtWidgets.QFileDialog.getOpenFileName(Ui_MainWindow, str, str, str)
Supported signatures:
PySide2.QtWidgets.QFileDialog.getOpenFileName(PySide2.QtWidgets.QWidget = None, str = '', str = '', str = '', str = '', PySide2.QtWidgets.QFileDialog.Options = Default(QFileDialog.Options))
I have read the python documentation for Qt ver 5.12 given here : https://doc.qt.io/qtforpython/PySide2/QtWidgets/QFileDialog.html
That didnt help either. Where did i go wrong??
Basically i want to :
Get a FileDialog -> Select an JPG File
Get the path of the file in python code -> Populate a GraphicsView with the image on the GUI
I am currently struggling with both the aspects
Any help will be appreciated..
You should not mix your program logic with the generated UI files, instead, create a QMainWindow class wrapper and inherit from both QMainWindow and the UI class.
As per your actual problem, you were just missing a reference to an object (for example, self) before passing the text to translate, I added a small helper method to handle that in the following example:
import sys
from PySide2 import QtCore, QtGui, QtWidgets
from PySide2.QtCore import QObject, QRectF, Qt
from PySide2.QtWidgets import QMainWindow, QFileDialog, QWidget, QVBoxLayout, QGraphicsScene, QGraphicsView
from PySide2.QtGui import QPixmap
class Ui_MainWindow(object):
def setupUi(self, MainWindow):
self.centralWidget = QtWidgets.QWidget(MainWindow)
self.gridLayout = QtWidgets.QGridLayout(self.centralWidget)
self.file_Select_Btn = QtWidgets.QPushButton(self.centralWidget)
self.file_Select_Btn.setGeometry(QtCore.QRect(1082, 80, 121, 28))
self.file_Select_Btn.setObjectName("file_Select_Btn")
self.file_Select_Btn.setText("Load Image")
self.gridLayout.addWidget(self.file_Select_Btn)
MainWindow.setCentralWidget(self.centralWidget)
QtCore.QMetaObject.connectSlotsByName(MainWindow)
class MainWindow(QMainWindow, Ui_MainWindow):
def __init__(self):
Ui_MainWindow.__init__(self)
QMainWindow.__init__(self)
# Initialize UI
self.setupUi(self)
self.file_Select_Btn.clicked.connect(self.showImage)
def tr(self, text):
return QObject.tr(self, text)
def showImage(self):
path_to_file, _ = QFileDialog.getOpenFileName(self, self.tr("Load Image"), self.tr("~/Desktop/"), self.tr("Images (*.jpg)"))
self.image_viewer = ImageViewer(path_to_file)
self.image_viewer.show()
class ImageViewer(QWidget):
def __init__(self, image_path):
super().__init__()
self.scene = QGraphicsScene()
self.view = QGraphicsView(self.scene)
layout = QVBoxLayout()
layout.addWidget(self.view)
self.setLayout(layout)
self.load_image(image_path)
def load_image(self, image_path):
pixmap = QPixmap(image_path)
self.scene.addPixmap(pixmap)
self.view.fitInView(QRectF(0, 0, pixmap.width(), pixmap.height()), Qt.KeepAspectRatio)
self.scene.update()
if __name__ == "__main__":
app = QtWidgets.QApplication(sys.argv)
main_window = MainWindow()
main_window.show()
sys.exit(app.exec_())

access instance variable by name from function

I need to make a UI for a class which makes a number of calculations from a set of variables. The code roughly looks like this:
class MainWindow:
def __init__(self):
pulse = Pulse()
self.var1_lineEdit.textEdited.connect(self.set_attribute(pulse, "var1", new_value))
self.var2_lineEdit.textEdited.connect(self.set_attribute(pulse, "var2", new_value))
self.var3_lineEdit.textEdited.connect(self.set_attribute(pulse, "var3", new_value))
....
def set_attribute(pulse, var_name, value):
# get value from line edit
# update value in pulse
# update other calculations
class Pulse:
def __init__(self):
var1 = 1
var2 = 2
var3 = 3
....
My problem here is how to code set_attribute. Is there a way to access individual variables of another class by passing the name as a function argument? I would like to avoid having to define a new function for each variable.
Or is there a simpler way to do this? I am not very familiar with OOP and the proper way of coding UIs.
EDIT
The signal/slot connections you've proposed will get you in trouble. Signals are connected to slots using the connect function, which accepts a python callable as its argument--not the function call itself. That's the difference between
widget.textChanged.connect(self.set_attribute) # right syntax
widget.textChanged.connect(self.set_attribute()) # wrong syntax
So then, how do you tell set_attribute what to do? ekhumoro informed me the error of my ways re: use of QSignalMapper. It's an outdated technique. Best to simply use lambda functions (or partials) to get the desired effect.
I updated my demo for use of lambdas
For the purposes of this demo, I've created a simple QMainWindow with two QLineEdit widgets and a QPushButton.
# file ui_main.py
from PyQt5 import QtCore, QtGui, QtWidgets
class Ui_MainWindow(object):
def setupUi(self, MainWindow):
MainWindow.setObjectName("MainWindow")
MainWindow.resize(359, 249)
self.centralwidget = QtWidgets.QWidget(MainWindow)
self.centralwidget.setObjectName("centralwidget")
self.formLayoutWidget = QtWidgets.QWidget(self.centralwidget)
self.formLayoutWidget.setGeometry(QtCore.QRect(0, 0, 351, 51))
self.formLayoutWidget.setObjectName("formLayoutWidget")
self.formLayout = QtWidgets.QFormLayout(self.formLayoutWidget)
self.formLayout.setObjectName("formLayout")
self.configParam1Label = QtWidgets.QLabel(self.formLayoutWidget)
self.configParam1Label.setObjectName("configParam1Label")
self.formLayout.setWidget(0, QtWidgets.QFormLayout.LabelRole, self.configParam1Label)
self.configEntry = QtWidgets.QLineEdit(self.formLayoutWidget)
self.configEntry.setObjectName("configEntry")
self.formLayout.setWidget(0, QtWidgets.QFormLayout.FieldRole, self.configEntry)
self.configParam2Label = QtWidgets.QLabel(self.formLayoutWidget)
self.configParam2Label.setObjectName("configParam2Label")
self.formLayout.setWidget(1, QtWidgets.QFormLayout.LabelRole, self.configParam2Label)
self.configEntry2 = QtWidgets.QLineEdit(self.formLayoutWidget)
self.configEntry2.setObjectName("configEntry2")
self.formLayout.setWidget(1, QtWidgets.QFormLayout.FieldRole, self.configEntry2)
self.pulseButton = QtWidgets.QPushButton(self.centralwidget)
self.pulseButton.setGeometry(QtCore.QRect(130, 140, 75, 23))
self.pulseButton.setObjectName("pulseButton")
MainWindow.setCentralWidget(self.centralwidget)
self.retranslateUi(MainWindow)
QtCore.QMetaObject.connectSlotsByName(MainWindow)
def retranslateUi(self, MainWindow):
_translate = QtCore.QCoreApplication.translate
MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow"))
self.configParam1Label.setText(_translate("MainWindow", "Config Param 1"))
self.configParam2Label.setText(_translate("MainWindow", "Config Param 2"))
self.pulseButton.setText(_translate("MainWindow", "GetPulse"))
In another file, after some imports, define Pulse--a simple class that contains two attributes
# file main.py
from PyQt5.QtCore import (QSignalMapper, pyqtSlot)
from PyQt5.QtWidgets import (QApplication, QMainWindow, QMessageBox)
from ui_main import Ui_MainWindow
class Pulse:
def __init__(self):
self.param_one = None
self.param_two = None
Now, define MainWindow, setting up its UI and giving it a Pulse:
class MainWindow(QMainWindow):
def __init__(self, parent=None):
super(MainWindow, self).__init__(parent)
self.pulse = Pulse()
self.ui = Ui_MainWindow()
self.ui.setupUi(self)
self.widget_one = self.ui.configEntry
self.widget_two = self.ui.configEntry2
self.pulse_button = self.ui.pulseButton
self.widget_one.textChanged.connect(lambda: self.widget_handler('param_one', self.widget_one.text()))
self.widget_one.textChanged.connect(lambda: self.widget_handler('param_two', self.widget_two.text()))
def widget_handler(self, attr, value):
setattr(self.pulse,attr,value)
def handler(self, idx):
widget, attr = self.attribute_widget_list[idx]
widget_value = widget.text()
setattr(self.pulse,attr,widget_value)
setattr is equivalent to, for example, self.pulse.param_one = widget_value.
To prove it works, let's use that QPushButton to probe the state of Pulse:
#pyqtSlot()
def on_pulseButton_clicked(self):
message = QMessageBox()
message.setText("{} - {}".format(self.pulse.param_one, self.pulse.param_two))
message.exec()
Here I'm using a different signal/slot connection scheme, which you can read about here
And here's how we run the script:
if __name__ == '__main__':
import sys
app = QApplication(sys.argv)
window = MainWindow()
window.show()
sys.exit(app.exec_())
Hope that helps!

PyQT - Multiple languages QT Designer auto.generated UI

I am using PyQt4 and I want to translate my UI created with QT Designer in different languages. I follow some tutorials, but I am not able to apply my translation files.
I created a TS file, edited with QT Linguist and release a QM file. I try to apply it to my app, but it is still in source language.
This is retranslate method:
def retranslateUi(self, CredentialsQT):
CredentialsQT.setWindowTitle(QtGui.QApplication.translate("CredentialsQT", "IngeMaster", None, QtGui.QApplication.UnicodeUTF8))
self.groupBox.setTitle(QtGui.QApplication.translate("CredentialsQT", "Credenciales de usuario", None, QtGui.QApplication.UnicodeUTF8))
self.label.setText(QtGui.QApplication.translate("CredentialsQT", "Usuario:", None, QtGui.QApplication.UnicodeUTF8))
self.label_2.setText(QtGui.QApplication.translate("CredentialsQT", "ContraseƱa:", None, QtGui.QApplication.UnicodeUTF8))
self.groupBox_2.setTitle(QtGui.QApplication.translate("CredentialsQT", "Lenguaje", None, QtGui.QApplication.UnicodeUTF8))
self.label_3.setText(QtGui.QApplication.translate("CredentialsQT", "Disponibles:", None, QtGui.QApplication.UnicodeUTF8))
self.comboBox.setItemText(0, QtGui.QApplication.translate("CredentialsQT", "Deustch", None, QtGui.QApplication.UnicodeUTF8))
self.comboBox.setItemText(1, QtGui.QApplication.translate("CredentialsQT", "English", None, QtGui.QApplication.UnicodeUTF8))
self.comboBox.setItemText(2, QtGui.QApplication.translate("CredentialsQT", "EspaƱol", None, QtGui.QApplication.UnicodeUTF8))
And this is main:
if __name__ == "__main__":
import sys
app = QtGui.QApplication(sys.argv)
archivo = 'Credentials_en.qm'
import os.path
if os.path.exists(archivo):
print "El fichero existe"
else:
print "El fichero no existe"
CredentialsQT = QtGui.QDialog()
ui = Ui_CredentialsQT()
ui.setupUi(CredentialsQT)
#from QtGui import QTranslator
translator=QtCore.QTranslator(app)
if translator.load(archivo, os.getcwd()):
app.installTranslator(translator)
CredentialsQT.show()
sys.exit(app.exec_())
Do you know what I am doing wrong?
There is probably some kind of issue with your code. See how this example works and adapt it to your needs:
#!/usr/bin/env python
#-*- coding:utf-8 -*-
#---------
# IMPORT
#---------
import sys, os, re
import sip
sip.setapi('QString', 2)
sip.setapi('QVariant', 2)
from PyQt4 import QtGui, QtCore
#---------
# DEFINE
#---------
class MyWindow(QtGui.QMainWindow):
def __init__(self, parent=None):
super(MyWindow, self).__init__(parent)
self.languageDirectory = "/usr/share/qt4/translations/"
self.languageLocale = "en"
self.languageTranslator = QtCore.QTranslator()
self.centralWidget = QtGui.QWidget(self)
self.labelLanguageSelect = QtGui.QLabel(self.centralWidget)
self.labelLanguageChange = QtGui.QLabel(self.centralWidget)
self.comboBoxLanguage = QtGui.QComboBox(self.centralWidget)
self.comboBoxLanguage.addItem("en" , "")
for filePath in os.listdir(self.languageDirectory):
fileName = os.path.basename(filePath)
fileMatch = re.match("qt_([a-z]{2,}).qm", fileName)
if fileMatch:
self.comboBoxLanguage.addItem(fileMatch.group(1), filePath)
self.sortFilterProxyModelLanguage = QtGui.QSortFilterProxyModel(self.comboBoxLanguage)
self.sortFilterProxyModelLanguage.setSourceModel(self.comboBoxLanguage.model())
self.comboBoxLanguage.model().setParent(self.sortFilterProxyModelLanguage)
self.comboBoxLanguage.setModel(self.sortFilterProxyModelLanguage)
self.comboBoxLanguage.currentIndexChanged.connect(self.on_comboBoxLanguage_currentIndexChanged)
self.comboBoxLanguage.model().sort(0)
self.buttonBox = QtGui.QDialogButtonBox(self.centralWidget)
self.buttonBox.setStandardButtons(QtGui.QDialogButtonBox.Yes|QtGui.QDialogButtonBox.Cancel)
self.buttonBox.clicked.connect(self.on_buttonBox_clicked)
self.layoutGrid = QtGui.QGridLayout(self.centralWidget)
self.layoutGrid.addWidget(self.labelLanguageSelect, 0, 0, 1, 1)
self.layoutGrid.addWidget(self.comboBoxLanguage, 0, 1, 1, 1)
self.layoutGrid.addWidget(self.labelLanguageChange, 1, 0, 1, 1)
self.layoutGrid.addWidget(self.buttonBox, 1, 1, 1, 1)
self.setCentralWidget(self.centralWidget)
self.retranslateUi()
self.resetLanguage()
self.updateButtons()
#QtCore.pyqtSlot()
def on_comboBoxLanguage_currentIndexChanged(self):
self.setLanguage()
self.updateButtons()
def changeEvent(self, event):
if event.type() == QtCore.QEvent.LanguageChange:
self.retranslateUi()
super(MyWindow, self).changeEvent(event)
#QtCore.pyqtSlot(QtGui.QAbstractButton)
def on_buttonBox_clicked(self, button):
buttonRole = self.buttonBox.buttonRole(button)
if buttonRole == QtGui.QDialogButtonBox.YesRole:
self.languageLocale = self.comboBoxLanguage.currentText()
self.updateButtons()
elif buttonRole == QtGui.QDialogButtonBox.RejectRole:
self.resetLanguage()
def resetLanguage(self):
index = self.comboBoxLanguage.findText(self.languageLocale)
self.comboBoxLanguage.setCurrentIndex(index)
def setLanguage(self):
app = QtGui.QApplication.instance()
app.removeTranslator(self.languageTranslator)
languageIndex = self.comboBoxLanguage.currentIndex()
languageFileName = self.comboBoxLanguage.itemData(languageIndex, QtCore.Qt.UserRole)
if languageFileName != "en":
languageFilePath = os.path.join(self.languageDirectory, languageFileName)
else:
languageFilePath = ""
self.languageTranslator = QtCore.QTranslator()
if self.languageTranslator.load(languageFilePath):
app.installTranslator(self.languageTranslator)
def updateButtons(self):
state = self.languageLocale != self.comboBoxLanguage.currentText()
self.buttonBox.button(QtGui.QDialogButtonBox.Cancel).setEnabled(state)
self.buttonBox.button(QtGui.QDialogButtonBox.Yes).setEnabled(state)
def retranslateUi(self):
# This text is not included in te .qm file.
# You'll have to create your own .qm file specifying the translation,
# otherwise it won't get translated.
self.labelLanguageSelect.setText(self.tr("Select Language:"))
self.labelLanguageChange.setText(self.tr("Change Language:"))
#---------
# MAIN
#---------
if __name__ == "__main__":
app = QtGui.QApplication(sys.argv)
app.setApplicationName('MyWindow')
main = MyWindow()
main.resize(333, 111)
main.show()
sys.exit(app.exec_())
I have finally made it to fix it. The problem was the translated words context.
My class was named "Ui_Credentials" and my script "Credentials.py". The .bat that generated python code from QtDesigner automaticaly added "Ui_" prefix to my class.
The solution is to change my script name adding also "Ui_" prefix like "Ui_Credentials.py".
Thanks for the helps!

Resources