PyQt4: How to load compiled ui-files correctly? - qt

I created a Qt resource file with all my ui files inside of it, I compiled that with pyrcc4 command-line in a python file, and then I loaded the ui files using loadUi. Here an example:
#!/usr/bin/env python
#-*- coding:utf-8 -*-
import os
import sys
from PyQt4.QtCore import Qt, QFile
from PyQt4.uic import loadUi
from PyQt4.QtGui import QDialog
from xarphus.gui import ui_rc
# I import the compiled qt resource file named ui_rc
BASE_PATH = os.path.dirname(os.path.abspath(__file__))
#UI_PATH = os.path.join(BASE_PATH, 'gui', 'create_user.ui')
UI_PATH = QFile(":/ui_file/create_user.ui")
# I want to load those compiled ui files,
# so I just create QFile.
class CreateUser_Window(QDialog):
def __init__(self, parent):
QDialog.__init__(self, parent)
# I open the created QFile
UI_PATH.open(QFile.ReadOnly)
# I read the QFile and load the ui file
self.ui_create_user = loadUi(UI_PATH, self)
# After then I close it
UI_PATH.close()
Well its works fine, but I have a problem. When I open the GUI-window once, everything works fine. After closing the window I try to open the same GUI-window again, I get ja long traceback.
Traceback (most recent call last): File "D:\Dan\Python\xarphus\xarphus\frm_mdi.py", line 359, in
create_update_form self.update_form = Update_Window(self) File
"D:\Dan\Python\xarphus\xarphus\frm_update.py", line 135, in init
self.ui_update = loadUi(UI_PATH, self) File
"C:\Python27\lib\site-packages\PyQt4\uic__init__.py", line 238, in
loadUi return DynamicUILoader(package).loadUi(uifile, baseinstance,
resource_suffix) File
"C:\Python27\lib\site-packages\PyQt4\uic\Loader\loader.py", line 71,
in loadUi return self.parse(filename, resource_suffix, basedir) File
"C:\Python27\lib\site-packages\PyQt4\uic\uiparser.py", line 984, in
parse document = parse(filename) File
"C:\Python27\lib\xml\etree\ElementTree.py", line 1182, in parse
tree.parse(source, parser) File
"C:\Python27\lib\xml\etree\ElementTree.py", line 657, in parse
self._root = parser.close() File
"C:\Python27\lib\xml\etree\ElementTree.py", line 1654, in close
self._raiseerror(v) File "C:\Python27\lib\xml\etree\ElementTree.py",
line 1506, in _raiseerror raise err xml.etree.ElementTree.ParseError:
no element found: line 1, column 0
Can everyone help me?

Maybe I have a solution, but I don't know if that is a perfectly pythonic.
Well, we know all python projects have an __ init __-file. We need it for initializing Python packages, right? Well I thought: Why not use this file? What did I do? I define in the __ init __ -file a function like so:
#!/usr/bin/env python
#-*- coding:utf-8 -*-
from PyQt4.uic import loadUi
from PyQt4.QtCore import Qt, QFile
def ui_load_about(self):
uiFile = QFile(":/ui_file/about.ui")
uiFile.open(QFile.ReadOnly)
self.ui_about = loadUi(uiFile)
uiFile.close()
return self.ui_about
Now in my "About_Window"-class I do this:
#!/usr/bin/env python
#-*- coding:utf-8 -*-
import os
import sys
from PyQt4.QtCore import Qt, QFile
from PyQt4.uic import loadUi
from PyQt4.QtGui import QDialog
import __init__ as ui_file
class About_Window(QDialog):
def __init__(self, parent):
QDialog.__init__(self, parent)
self.ui_about = ui_file.ui_load_about(self)
You see I importe the package-file (__ init __-file) as ui_file and then I call the function and save the return of the function in the variable self.ui_about.
In my case I open the About_Window from a MainWindow(QMainWindow), and it looks like so:
def create_about_form(self):
self.ui_about = About_Window(self)
# Now when I try to show (show()-method) a window I get two windows
# The reason is: I open and load the ui files from compiled
# qt resorce file that was define in __init__-module.
# There is a function that opens the resource file, reads
# the ui file an closes and returns the ui file back
# That's the reason why I have commented out this method
#self.ui_about.show()
You see I commented out the show()-method. It works without this method. I only define the About_Window()-class. Well I know that isn't maybe the best solution, but it works. I can open the window again and again without traceback.
If you have a better solution or idea let me know :-)

Related

Qt Designer Storing and Parsing User Input from Line Edit using Python to Robot Operating System (ROS)

I am currently trying to create a GUI that allows users to type in whatever words they want to be translated into R2-D2's voice.
I have used Qt 5 Designer to create a user input using Line Edit and a button that will publish the user input to a specified topic in ROS. I have also converted it into a python file using pyuic5 -o as r2d2_sound_control.py and I have a main file called main_r2d2_sound_control.py that I will run to initialise the GUI.
How do you store and parse a string from Line Edit using python? I do not know how to declare the string from the user input and parse it when the button is clicked. I'm using pyqt 4
Thank you in advance.
Link to R2-D2 voice package in GitHub https://github.com/koide3/ros2d2
Contents of r2d2_sound_control.py:
# -*- coding: utf-8 -*-
# Form implementation generated from reading ui file 'r2d2_sound_control.ui'
#
# Created by: PyQt5 UI code generator 5.10.1
#
# WARNING! All changes made in this file will be lost!
from PyQt5 import QtCore, QtGui, QtWidgets
class Ui_Dialog(object):
def setupUi(self, Dialog):
Dialog.setObjectName("Dialog")
Dialog.resize(505, 114)
self.pushButton_speak = QtWidgets.QPushButton(Dialog)
self.pushButton_speak.setGeometry(QtCore.QRect(300, 40, 89, 25))
self.pushButton_speak.setObjectName("pushButton_speak")
self.lineEdit_speak = QtWidgets.QLineEdit(Dialog)
self.lineEdit_speak.setGeometry(QtCore.QRect(60, 40, 201, 25))
self.lineEdit_speak.setObjectName("lineEdit_speak")
self.retranslateUi(Dialog)
self.pushButton_speak.clicked.connect(Dialog.clicked_speak)
self.lineEdit_speak.returnPressed.connect(Dialog.clicked_speak)
QtCore.QMetaObject.connectSlotsByName(Dialog)
def retranslateUi(self, Dialog):
_translate = QtCore.QCoreApplication.translate
Dialog.setWindowTitle(_translate("Dialog", "Dialog"))
self.pushButton_speak.setText(_translate("Dialog", "Say Out"))
Contents of main_r2d2_sound_control.py
#! /usr/bin/python3
# -*- coding: utf-8 -*-
# GUI
import sys
from PyQt5.QtCore import *
from PyQt5.QtWidgets import *
#Import the automatically generated file
from r2d2_sound_control import Ui_Dialog
# ROS
import rospy
from std_msgs.msg import String
class Test(QDialog):
def __init__(self,parent=None):
# GUI
super(Test, self).__init__(parent)
self.ui = Ui_Dialog()
self.ui.setupUi(self)
# ROS pub settings
self.r2d2_sound_controller_String = String()
self.pub_r2d2_sound_controller_speak = rospy.Publisher('/ros2d2_node/speak',String,queue_size=10)
def speak_content(self):
self.input = string(lineEdit_speak)
self.lineEdit_speak.setText(self.text())
def clicked_speak(self):
"""
The slot name specified in Qt Designer.
Write the process you want to execute with the "Say Out" button.
"""
self.r2d2_sound_controller_String.data = text()
self.pub_r2d2_sound_controller_speak.publish(self.r2d2_sound_controller_String)
self.r2d2_sound_controller_String.data = ''
if __name__ == '__main__':
rospy.init_node('r2d2_sound_talker')
app = QApplication(sys.argv)
window = Test()
window.show()
sys.exit(app.exec_())
I have managed to fix it thanks to my friend. I have made the following changes to main_r2d2_sound_control.py
#! /usr/bin/python3
# -*- coding: utf-8 -*-
# GUI
import sys
from PyQt5.QtCore import *
from PyQt5.QtWidgets import *
#Import the automatically generated file
from r2d2_head_gripper_sound import Ui_Dialog
# ROS
import rospy
from std_msgs.msg import String
class Test(QDialog):
def __init__(self,parent=None):
# GUI
super(Test, self).__init__(parent)
self.ui = Ui_Dialog()
self.ui.setupUi(self)
# ROS pub settings
self.r2d2_sound_controller_String = String()
self.pub_r2d2_sound_controller_speak = rospy.Publisher('/ros2d2_node/speak',String,queue_size=10)
self.r2d2_sound_controller_String.data = ''
def clicked_speak(self):
"""
The slot name specified in Qt Designer.
Write the process you want to execute with the "Say Out" button.
"""
text = self.ui.lineEdit_speak.text()
self.r2d2_sound_controller_String.data = text
self.pub_r2d2_sound_controller_speak.publish(self.r2d2_sound_controller_String)
if __name__ == '__main__':
rospy.init_node('r2d2_head_and_gripper_talker')
app = QApplication(sys.argv)
window = Test()
window.show()
sys.exit(app.exec_())

Running all python unittests from different modules as a suite having parameterized class constructor

I am working on a design pattern to make my python unittest as a POM, so far I have written my page classes in modules HomePageObject.py,FilterPageObject.py, my base class (for common stuff)TestBase in BaseTest.py, my testcase modules are TestCase1.py and TestCase2.py and one runner module runner.py.
In runner class i am using loader.getTestCaseNames to get all the tests from a testcase class of a module. In both the testcase modules the name of the test class is same 'Test' and also the method name is same 'testName'
Since the names are confilicting while importing it in runner, only one test is getting executed. I want python to scan all the modules that i specify for tests in them and run those even the name of classes are same.
I got to know that nose might be helpful in this, but not sure how i can implement it here. Any advice ?
BaseTest.py
from selenium import webdriver
from selenium.webdriver.support.wait import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver import ChromeOptions
import unittest
class TestBase(unittest.TestCase):
driver = None
def __init__(self,testName,browser):
self.browser = browser
super(TestBase,self).__init__(testName)
def setUp(self):
if self.browser == "firefox":
TestBase.driver = webdriver.Firefox()
elif self.browser == "chrome":
options = ChromeOptions()
options.add_argument("--start-maximized")
TestBase.driver = webdriver.Chrome(chrome_options=options)
self.url = "https://www.airbnb.co.in/"
self.driver = TestBase.getdriver()
TestBase.driver.implicitly_wait(10)
def tearDown(self):
self.driver.quit()
#staticmethod
def getdriver():
return TestBase.driver
#staticmethod
def waitForElementVisibility(locator, expression, message):
try:
WebDriverWait(TestBase.driver, 20).\
until(EC.presence_of_element_located((locator, expression)),
message)
return True
except:
return False
TestCase1.py and TestCase2.py (same)
from airbnb.HomePageObject import HomePage
from airbnb.BaseTest import TestBase
class Test(TestBase):
def __init__(self,testName,browser):
super(Test,self).__init__(testName,browser)
def testName(self):
try:
self.driver.get(self.url)
h_page = HomePage()
f_page = h_page.seachPlace("Sicily,Italy")
f_page.selectExperience()
finally:
self.driver.quit()
runner.py
import unittest
from airbnb.TestCase1 import Test
from airbnb.TestCase2 import Test
loader = unittest.TestLoader()
test_names = loader.getTestCaseNames(Test)
suite = unittest.TestSuite()
for test in test_names:
suite.addTest(Test(test,"chrome"))
runner = unittest.TextTestRunner()
result = runner.run(suite)
Also even that one test case is getting passed, some error message is coming
Ran 1 test in 9.734s
OK
Traceback (most recent call last):
File "F:\eclipse-jee-neon-3-win32\eclipse\plugins\org.python.pydev.core_6.3.3.201805051638\pysrc\runfiles.py", line 275, in <module>
main()
File "F:\eclipse-jee-neon-3-win32\eclipse\plugins\org.python.pydev.core_6.3.3.201805051638\pysrc\runfiles.py", line 97, in main
return pydev_runfiles.main(configuration) # Note: still doesn't return a proper value.
File "F:\eclipse-jee-neon-3-win32\eclipse\plugins\org.python.pydev.core_6.3.3.201805051638\pysrc\_pydev_runfiles\pydev_runfiles.py", line 874, in main
PydevTestRunner(configuration).run_tests()
File "F:\eclipse-jee-neon-3-win32\eclipse\plugins\org.python.pydev.core_6.3.3.201805051638\pysrc\_pydev_runfiles\pydev_runfiles.py", line 773, in run_tests
all_tests = self.find_tests_from_modules(file_and_modules_and_module_name)
File "F:\eclipse-jee-neon-3-win32\eclipse\plugins\org.python.pydev.core_6.3.3.201805051638\pysrc\_pydev_runfiles\pydev_runfiles.py", line 629, in find_tests_from_modules
suite = loader.loadTestsFromModule(m)
File "C:\Python27\lib\unittest\loader.py", line 65, in loadTestsFromModule
tests.append(self.loadTestsFromTestCase(obj))
File "C:\Python27\lib\unittest\loader.py", line 56, in loadTestsFromTestCase
loaded_suite = self.suiteClass(map(testCaseClass, testCaseNames))
TypeError: __init__() takes exactly 3 arguments (2 given)
I did this by searching for all the modules of test classes with a pattern and then used __import__(modulename) and called its Test class with desired parameters,
Here is my runner.py
import unittest
import glob
loader = unittest.TestLoader()
suite = unittest.TestSuite()
test_file_strings = glob.glob('Test*.py')
module_strings = [str[0:len(str)-3] for str in test_file_strings]
for module in module_strings:
mod = __import__(module)
test_names =loader.getTestCaseNames(mod.Test)
for test in test_names:
suite.addTest(mod.Test(test,"chrome"))
runner = unittest.TextTestRunner()
result = runner.run(suite)
This worked but still looking for some organized solutions.
(Not sure why second time its showing Ran 0 tests in 0.000s )
Finding files... done.
Importing test modules ... ..done.
----------------------------------------------------------------------
Ran 2 tests in 37.491s
OK
----------------------------------------------------------------------
Ran 0 tests in 0.000s
OK

Load svg from Qt resource to string and change color

I try to change the color of an button icon at runtime. If I have the svg as xml its easy to do. Is it possible to load the xml text representation from an resource file?
Solved: Yes it's possible:
#!/usr/bin/env python
import sip
try:
sip.setapi('QString', 2)
sip.setapi('QVariant', 2)
except ValueError, e:
log.error(e)
from PyQt4.QtGui import *
from PyQt4.QtCore import *
from PyQt4.QtSvg import *
import sys
import resources_rc
if __name__ == '__main__':
app = QApplication(sys.argv)
f = QFile(":/icons/icons/svg/draw-freehand.svg")
if f.open(QFile.ReadOnly | QFile.Text):
textStream = QTextStream(f)
svgData = textStream.readAll()
f.close()
svg = QSvgRenderer(QByteArray(svgData))
qim = QImage(32, 32, QImage.Format_ARGB32)
qim.fill(0)
painter = QPainter()
painter.begin(qim)
svg.render(painter)
painter.end()
qim.save('test2.png')
You can read the SVG source code from QRC into a QString and do string manipulation from there:
Reading from and writing to file in The Qt Resource System (qt 5.0.2)

PyQt5 file dialog not showing up

I have connected a QPushButton to a method that call file dialog. The simplified code look like this:
def init_buttons(self):
self.browse_button = QPushButton('&Browse')
self.browse_button.clicked.connect(self.browse_file)
def browse_file(self):
file_name = QFileDialog.getExistingDirectory()
# Just for checking
print(file_name)
Sometimes QFileDialog won't showing up. The process is indeed running, since the main class/widget doesn't response to my clicking. Sometimes it's showing up.
If QFileDialog doesn't show up, with pycharm, I have to stop and kill process to end the program. If I run the program directly from terminal, I have to manually end the running process to end the program. I can't figure out what causing this, since terminal not showing any exception or warning.
So, what is this?
The parameters for the getExistingDirectory were wrong. Please try this. Also, I have added further information in my pull request.
import os
def browse_file(self):
self.save_dir = QFileDialog.getExistingDirectory(self,
"Open Save Directory", os.path.expanduser('~'))
print(self.save_dir)
#!/usr/bin/python3
# -*- coding: utf-8 -*-
import sys
from PyQt5.QtWidgets import (QMainWindow, QTextEdit,
QAction,QMessageBox, QFileDialog, QApplication,QPushButton,QInputDialog,QLineEdit)
from PyQt5.QtGui import QIcon
class Example(QMainWindow):
def __init__(self):
super().__init__()
self.initUI()
def initUI(self):
self.fileName=""
self.text=""
btn1 = QPushButton("Encrypt", self)
btn1.clicked.connect(self.onBtn1)
self.show()
def onBtn1(self):
self.fileName, _ = QFileDialog.getOpenFileName(self, 'Open file', '/Users/Jarvis/Desktop/')
if __name__ == '__main__':
app = QApplication(sys.argv)
ex = Example()
sys.exit(app.exec_())

Using functions from a class in another file to a class in my second file, python3

I have two python files, one is the gui, the other contains all of the functions, say i have a class named Backend like in the code below, and one of its functions is "print1(self)", and i want to use that "print1" function inside of the second file in the class named retranslateUi(self, Form), how would i do it?
First file
__author__ = 'Richard'
import sqlite3
conn = sqlite3.connect('realscheduler.db')
c = conn.cursor()
c.execute('pragma foreign_keys = ON;')
class Backend:
def print1(self):
print('Works')
Second file
# -*- coding: utf-8 -*-
# Form implementation generated from reading ui file 'untitled.ui'
#
# Created by: PyQt5 UI code generator 5.4.1
#
# WARNING! All changes made in this file will be lost!
from PyQt5 import QtCore, QtGui, QtWidgets
class Ui_Form(object):
def setupUi(self, Form):
Form.setObjectName("Form")
Form.resize(400, 300)
self.horizontalLayout = QtWidgets.QHBoxLayout(Form)
self.horizontalLayout.setObjectName("horizontalLayout")
self.verticalLayout = QtWidgets.QVBoxLayout()
self.verticalLayout.setObjectName("verticalLayout")
spacerItem = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding)
self.verticalLayout.addItem(spacerItem)
self.label = QtWidgets.QLabel(Form)
self.label.setObjectName("label")
self.verticalLayout.addWidget(self.label)
self.pushButton = QtWidgets.QPushButton(Form)
self.pushButton.setObjectName("pushButton")
self.verticalLayout.addWidget(self.pushButton)
spacerItem1 = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding)
self.verticalLayout.addItem(spacerItem1)
self.horizontalLayout.addLayout(self.verticalLayout)
self.retranslateUi(Form)
QtCore.QMetaObject.connectSlotsByName(Form)
def retranslateUi(self, Form):
_translate = QtCore.QCoreApplication.translate
Form.setWindowTitle(_translate("Form", "Form"))
self.label.setText(_translate("Form", "Labellabellabel"))
self.pushButton.setText(_translate("Form", "Print"))
First you should create a main entry point to the application like so. I will call it app.py and the generated Qt Designer file view.py for this example:
from PyQt5.QtWidgets import (QMainWindow, QApplication)
# importing the GUI from the designer file
from view import Ui_MainWindow
# importing the database file Backend class
from database import Backend
class Main(QMainWindow, Ui_MainWindow):
def __init__(self, parent=None):
super(Main, self).__init__(parent)
self.setupUi(self)
# this will connect your push button the the function
self.pushButton.clicked.connect(Backend.print1)
if __name__ == "__main__":
import sys
QCoreApplication.setApplicationName("app name")
QCoreApplication.setApplicationVersion("app version")
QCoreApplication.setOrganizationName("Your name")
QCoreApplication.setOrganizationDomain("Your URL")
app = QApplication(sys.argv)
form = Main()
form.show()
sys.exit(app.exec_())
PyQt follows the Model-View architecture so this is a nice way to bind your functionality / data away from the graphical components of the application.
You have to import the first file into the second one as import first_filename as t then create class object p=t.classname then use any function you want which is declared in the class

Resources