Package: qutie
QutieYet another pythonic UI library for rapid prototyping using PyQt5.Quick startimportqutieasuiapp=ui.Application()window=ui.Widget(title="Example",icon='orange',width=320,height=240,layout=ui.Column(ui.Label("Hello world!"),ui.Row(ui.Button("Go!",clicked=lambda:ui.show_info(text="Hello world!")),ui.Button("Quit",clicked=app.quit))))window.show()app.run()DocumentationQutie (pronounced ascutie) provides a simple and easy to use pythonic
interface to PyQt5.InstallpipinstallqutieApplicationA singleApplicationobject must be created before other widgets. To make use
of the event system the application event loop must be executed.importqutieasui# Create an application object.app=ui.Application(name='app',version='1.0')# Create a window.window=ui.MainWindow()window.resize(800,600)window.show()# Run the event loop.app.run()WidgetsAny widget can be a top level window or part of another widget using thelayoutproperty. All properties can be assigned using the constructor.window=ui.Widget(title="Example",width=320,height=240)To make a top level window visible use propertyvisibleor call methodshow().window.show()window.visible=True# equivalent to showLayoutsThe simplified layout system provides a horizontalRowand a verticalColumnbox. Items can be added while constructing the layout or using list like methodsappendandinsert. The consumed space of every child widget can be adjusted
using thestretchattribute.window.layout=ui.Row(ui.Column(...),ui.Column(ui.Row(...),ui.Row(...),ui.Row(...),stretch=(1,0,0)),stretch=(2,3))Inputs# Single line text inputtext=ui.Text(value="spam")# Numeric inputnumber=ui.Number(value=4,minimum=0,maximum=10,step=1.0,decimals=1)# A multi line text areatextarea=ui.TextArea(value="Lorem ipsum et dolor.")EventsEvents provide a simplified interface to Qt's signal and slot system. Events can
be emitted from any class inheriting fromObjectby calling methodemit().# Use any callable class attribute as event callback.window.issue_call=lambda:print("Call to action!")# Emit an event executing attribute `issue_call` (if callable).window.emit('issue_call')Events can also propagate positional and keyword arguments.# Use any callable class attribute as event callback.window.update_progress=lambdaa,b:print(f"Progress:{a}of{b}")# Emit an event executing attribute `update_progress` (if callable).window.emit('update_progress',42,100)Many widgets provide predefined events.# Assigning callback functionsui.Number(value=4,changed=on_change,editing_finished=on_edited)TimersCall repeating or delayed events using timers.timer=ui.Timer(interval=1.0,timeout=lambda:print("Done!"))timer.start()Functionsingle_shotexposes a convenient single shot timer.ui.single_shot(interval=1.0,timeout=lambda:print("Done!"))Note that timer events are only processed when running the application event
loop.SettingsPersistent settings can be stored/restored using aSettingsobject as context
manager. It provides application wide settings as a JSON dictionary.withui.Settings()assettings:value=settings.get('key','default')settings['key']=valueUse attributefilenameto inspect the persistent JSON data.>>>ui.Settings().filename'/home/user/.config/app.qutie'MenusMenu bars and menus behave like python lists.window=ui.MainWindow()file_menu=window.menubar.append("&File")quit_action=file_menu.append("&Quit")quit_action.triggered=window.closefoo_menu=window.menubar.insert(window.menubar.index(file_menu),"&Foo")file_menu=window.menubar.remove(file_menu)ToolbarsToolbars also behave like python lists, the main window toolbars property
behaves like a set.window=ui.MainWindow()toolbar=window.toolbars.add("toolbar")toolbar.append(quit_action)toolbar.insert(quit_action)window.toolbars.remove(toolbar)WorkersTheWorkerclass provides a convenient way to work with background threads.
Use attributetargetto assign the function to be executed in the background.defcalculate(worker):foriinrange(100):...worker=ui.Worker(target=calculate)worker.start()Important:use only the event system to propagate information from inside
the worker. Do not access widgets from within the worker function.defcalculate(worker):foriinrange(100):# Emit custom events.worker.emit('progress',i,100)worker.emit('message',"All ok...")worker=ui.Worker(target=calculate)# Assign custom event callbacks.worker.progress=lambdastep,max:print(f"progress:{step}/{max}")worker.message=lambdamsg:print(f"message:{msg}")worker.start()To control worker lifetime use methodstop()and attributestopping.defcalculate(worker):whilenotworker.stopping:...worker=ui.Worker(target=calculate)worker.start()...worker.stop()To wait for a worker to actually stop use methodjoin().worker.stop()worker.join()ExampleA simple dialog with progress bar running a calculation in the background.importrandomimporttimeimportqutieasuiclassDialog(ui.Dialog):def__init__(self,**kwargs):super().__init__(**kwargs)# Create workerself.worker=ui.Worker(target=self.calculate)self.worker.finished=self.closeself.worker.update_progress=self.update_progress# Create layoutself.progress_bar=ui.ProgressBar()self.layout=self.progress_bardefrun(self):# Start, stop and join workerself.worker.start()super().run()self.worker.stop()self.worker.join()defupdate_progress(self,value,maximum):self.progress_bar.maximum=maximumself.progress_bar.value=valuedefcalculate(self,worker):n=32foriinrange(n):ifworker.stopping:break# Emit custom eventworker.emit('update_progress',i,n)time.sleep(random.random())app=ui.Application()dialog=Dialog(title="Worker")dialog.run()Something missing?Any underlying PyQt5 instance can be accessed directly using propertyqt.
This also enables to mix in custom PyQt5 classes and instances.widget.qt.setWindowTitle("Spam!")widget.qt.customContextMenuRequested.connect(lambdapos:None)widget.qt.layout().addWidget(QtWidgets.QPusbButton())LicenseQutie is licensed under theGNU General Public License Version 3.