Reputation: 3869
I am using Qt Designer for designing my user interfaces, and I want to build custom widgets which could be a combination of existing qt widgets such as a QLabel and QPushButton attached screenshot
Now I would like this to be independent with it's own business logic, signals and slots in a separate python file, but would want to add this as a component to my main screen.
I tried above by creating seprate ui file of type widget, but when I promote that from my MainWindow, it won't show up, and the code generated by pyuic would add it to the layout, but it is not rendered in main window.
Is there a way of doing that in PyQt and QDesigner?
EDIT:
Here is the actual code:
timer.py:
from PyQt4 import QtGui, QtCore
from datetime import timedelta, datetime
from logbook import info
import timer_ui
class Timer(QtGui.QWidget, timer_ui.Ui_TimerWidget):
start_time = None
running = False
total_time = 0
time_spent = ''
activity = None
stopwatch = 0
elapsed_time = None
total_elapsed_time = timedelta()
def __init__(self, parent=None):
super(self.__class__, self).__init__(parent)
self.setupUi(parent) #for custom widget parent is main window here which is dashboard
self.lcdNumber.setDigitCount(12)
self.qt_timer = QtCore.QTimer(self)
self.qt_timer.timeout.connect(self.timer_event)
self.qt_timer.start(1000)
self.goButton.clicked.connect(self.go)
self.breakButton.clicked.connect(self.break_timer)
def go(self):
# date text format .strftime('%a, %d %b %Y %H:%M:%S')
self.start_time = datetime.now().replace(microsecond=0)
self.running = True
self.goButton.setEnabled(False)
self.breakButton.setEnabled(True)
def break_timer(self):
''' break finishes the activity '''
break_time = datetime.now().replace(microsecond=0)
self.activity.log_break(break_time.isoformat())
self.activity = None # activity completed
self.total_elapsed_time += self.elapsed_time
info(self.total_elapsed_time)
self.running = False
# self.lcdNumber.display(str(self.timer.get_elapsed()))
self.goButton.setEnabled(True)
self.breakButton.setEnabled(False)
def timer_event(self):
'''Updates the widget every second'''
if self.running == True:
current_time = datetime.now().replace(microsecond=0)
# if self.elapsed_time is None:
self.elapsed_time = current_time - self.start_time
# else:
#self.elapsed_time += current_time - self.timer.start_time.replace(microsecond=0)
if self.total_elapsed_time is not None:
self.lcdNumber.display(str(self.elapsed_time + self.total_elapsed_time))
else:
self.lcdNumber.display(str(self.elapsed_time))
mainwindow.py:
# -*- coding: utf-8 -*-
# Form implementation generated from reading ui file 'dashboard.ui'
#
# Created: Sat Mar 19 11:40:35 2016
# by: PyQt4 UI code generator 4.10.4
#
# WARNING! All changes made in this file will be lost!
from PyQt4 import QtCore, QtGui
try:
_fromUtf8 = QtCore.QString.fromUtf8
except AttributeError:
def _fromUtf8(s):
return s
try:
_encoding = QtGui.QApplication.UnicodeUTF8
def _translate(context, text, disambig):
return QtGui.QApplication.translate(context, text, disambig, _encoding)
except AttributeError:
def _translate(context, text, disambig):
return QtGui.QApplication.translate(context, text, disambig)
class Ui_MainWindow(object):
def setupUi(self, MainWindow):
MainWindow.setObjectName(_fromUtf8("MainWindow"))
MainWindow.resize(772, 421)
self.centralwidget = QtGui.QWidget(MainWindow)
self.centralwidget.setObjectName(_fromUtf8("centralwidget"))
self.verticalLayout = QtGui.QVBoxLayout()
self.verticalLayout.setObjectName(_fromUtf8("verticalLayout"))
self.widget = Timer(self.centralwidget)
self.verticalLayout.addWidget(self.widget)
self.horizontalLayout = QtGui.QHBoxLayout()
self.horizontalLayout.setObjectName(_fromUtf8("horizontalLayout"))
self.userNameLabel = QtGui.QLabel(self.centralwidget)
self.userNameLabel.setObjectName(_fromUtf8("userNameLabel"))
self.horizontalLayout.addWidget(self.userNameLabel)
self.logoutButton = QtGui.QPushButton(self.centralwidget)
self.logoutButton.setEnabled(True)
self.logoutButton.setObjectName(_fromUtf8("logoutButton"))
self.horizontalLayout.addWidget(self.logoutButton)
self.verticalLayout.addLayout(self.horizontalLayout)
self.listView = QtGui.QListView(self.centralwidget)
self.listView.setObjectName(_fromUtf8("listView"))
self.verticalLayout.addWidget(self.listView)
MainWindow.setCentralWidget(self.centralwidget)
self.statusbar = QtGui.QStatusBar(MainWindow)
self.statusbar.setObjectName(_fromUtf8("statusbar"))
MainWindow.setStatusBar(self.statusbar)
self.menuBar = QtGui.QMenuBar(MainWindow)
self.menuBar.setGeometry(QtCore.QRect(0, 0, 772, 23))
self.menuBar.setObjectName(_fromUtf8("menuBar"))
MainWindow.setMenuBar(self.menuBar)
self.retranslateUi(MainWindow)
QtCore.QMetaObject.connectSlotsByName(MainWindow)
def retranslateUi(self, MainWindow):
MainWindow.setWindowTitle(_translate("MainWindow", "Title", None))
self.userNameLabel.setText(_translate("MainWindow", "You are now logged in as", None))
self.logoutButton.setText(_translate("MainWindow", "Logout", None))
from timer import Timer
timer_ui.py:
# -*- coding: utf-8 -*-
# Form implementation generated from reading ui file 'timer.ui'
#
# Created: Sat Mar 19 11:41:40 2016
# by: PyQt4 UI code generator 4.10.4
#
# WARNING! All changes made in this file will be lost!
from PyQt4 import QtCore, QtGui
try:
_fromUtf8 = QtCore.QString.fromUtf8
except AttributeError:
def _fromUtf8(s):
return s
try:
_encoding = QtGui.QApplication.UnicodeUTF8
def _translate(context, text, disambig):
return QtGui.QApplication.translate(context, text, disambig, _encoding)
except AttributeError:
def _translate(context, text, disambig):
return QtGui.QApplication.translate(context, text, disambig)
class Ui_TimerWidget(object):
def setupUi(self, TimerWidget):
TimerWidget.setObjectName(_fromUtf8("TimerWidget"))
TimerWidget.resize(412, 52)
self.horizontalLayout = QtGui.QHBoxLayout(TimerWidget)
self.horizontalLayout.setObjectName(_fromUtf8("horizontalLayout"))
self.label = QtGui.QLabel(TimerWidget)
self.label.setObjectName(_fromUtf8("label"))
self.horizontalLayout.addWidget(self.label)
self.lcdNumber = QtGui.QLCDNumber(TimerWidget)
self.lcdNumber.setAutoFillBackground(False)
self.lcdNumber.setNumDigits(12)
self.lcdNumber.setSegmentStyle(QtGui.QLCDNumber.Flat)
self.lcdNumber.setObjectName(_fromUtf8("lcdNumber"))
self.horizontalLayout.addWidget(self.lcdNumber)
self.goButton = QtGui.QPushButton(TimerWidget)
self.goButton.setObjectName(_fromUtf8("goButton"))
self.horizontalLayout.addWidget(self.goButton)
self.breakButton = QtGui.QPushButton(TimerWidget)
self.breakButton.setObjectName(_fromUtf8("breakButton"))
self.horizontalLayout.addWidget(self.breakButton)
self.retranslateUi(TimerWidget)
#QtCore.QMetaObject.connectSlotsByName(TimerWidget)
def retranslateUi(self, TimerWidget):
#TimerWidget.setWindowTitle(_translate("TimerWidget", "Form", None))
self.label.setText(_translate("TimerWidget", "Total hours spent", None))
self.goButton.setText(_translate("TimerWidget", "Go!", None))
self.breakButton.setText(_translate("TimerWidget", "Break", None))
Upvotes: 1
Views: 2280
Reputation: 120578
Promoted widgets are just placeholders for standard Qt widgets. You cannot create a custom widget for Qt Designer that way.
It can be done, but the process is much more complicated than simple widget promotion. See Writing Qt Designer Plugins in the PyQt docs, and for a detailed tutorial, see Using Python Custom Widgets In Qt Designer on the Python Wiki. The PyQt source code also has many more examples (look in examples/designer/plugins).
EDIT:
There are two problems with your code. Firstly, you are passing the wrong argument to setupUi
in the Timer
class. You should fix it like this:
class Timer(QtGui.QWidget, timer_ui.Ui_TimerWidget):
...
def __init__(self, parent=None):
super(Timer, self).__init__(parent)
self.setupUi(self) # pass in self, not parent
Secondly, you edited the mainwindow.py file and broke one of the layouts. Never, ever edit the modules generated by pyuic
! The line you broke is this one:
# self.verticalLayout = QtGui.QVBoxLayout()
self.verticalLayout = QtGui.QVBoxLayout(self.centralwidget)
But don't try to fix this by editing - instead, make sure you regenerate all the ui modules with pyuic
so you get back to clean, unedited files again.
Upvotes: 1
Reputation: 3945
I do this all the time, i.e build Custom widgets and use them inside my main window.
I don't know what is the top level widget for your custom widget, but it should preferably be QWidget
or QFrame
from the list of Containers
in the Qt Designer and add the child widgets inside it, let's name this custom widget file as custom.ui
.
Next, create a Python class as follows:
Form, Base = uic.loadUiType('/path/to/custom.ui') # this path should be a relative path. For testing you can use absolute path.
class CustomWidget(Form, Base):
def __init__(self, parent=None):
super(CustomWidget, self).__init__(parent)
self.setupUi(self)
You can add any number of signals and slots for the custom logic to the above class.
Similarly create a class for your main window and then create an object of CustomWidget
inside that main class and add that object to the layout.
Form2, Base2 = uic.loadUiType('/path/to/dashboard.ui') # this path should be a relative path. For testing you can use absolute path.
class Window(Form2, Base2):
def __init__(self, parent=None):
super(Window, self).__init__(parent)
self.setupUi(self)
self.cWidget = CustomWidget(self)
self.layout.addWidget(self.cWidget)
Note: This code is compatible with Python 2.x, if you are using Python 3.x, make necessary changes. This code is not tested, so syntax errors must also be resolved if found.
Upvotes: 0