[prev in list] [next in list] [prev in thread] [next in thread] 

List:       pykde
Subject:    Re: [PyQt] Confusion about load.uic() and import regarding pyinstaller
From:       Hans =?UTF-8?Q?J=C3=B6rg?= Maurer <hjm () pmeonline ! net>
Date:       2019-03-13 5:38:38
Message-ID: b9865a3964c94df0099d49d94e00779b () pmeoffice ! de
[Download RAW message or body]

[Attachment #2 (multipart/alternative)]


@ Maurizio

Thank you so much for clearing the nodal in my brain. Beautiful music
you make, btw. 

Regards Hans









Here the link to the SO Question mentioned in the mail below:
https://stackoverflow.com/questions/46515179/subclassing-of-widgets-which-are-loaded-by-uic-loadui




After many years of playing around with PyQt I've found "my" optimal
setup for a good environment allowing simpler coding and integration
with .ui files created within Designer. I'd also like to add that the
documentation about this is not always clear, and it sometimes "makes
sense" only whenever you've completely understood how Qt, PyQt and the
whole GUI environment works.


Let me share how I usually work.


- All main windows (QMainWindow and QDialog, but QWidget too) are only
saved to .ui files, and I load their ui through loadUi(). While
"building" with pyuic might be better for various reasons (paths,
mainly), working with plain raw ui files avoids confusion: sometimes
(a lot of times, in my case, it can be simple fatigue or distraction
after hours of coding) you edit a widget in Designer and then you
forget that you've to recreate the python ui file, then after minutes
of trying to understand why something is not working as it should, you
remember... This is annoying, and makes you lose a *lot* of time.
- Due to the previous point, all windows that use an .ui file only
have to inherit from their base Qt class; the only drawback is that
you've to be careful to never use object names that might conflict
with python naming standards and QWidget/QObject property/function
names: for example, "style", "cursor" or "layout". The huge advantage
is that you don't need to refer to the "self.ui", and everything is
transparently available as a property/method of the main widget class.
- All custom widgets of a GUI loaded from an .ui file that require
some sort of customization that is not a public function or cannot be
easily "fixed" through an eventFilter are "promoted widgets".


The last point is probably the one that creates more confusion above
everything else. But, while it might seem an annoying thing to do,
once you've got the hand of it, it's fairly easy to implement a widget
just by subclassing only what you need.

Let's assume you've a QMainWindow with a QListView for which you only
need to print out drop events, and let's assume you'll use
"myprogram.py" as the file for your python program.


- Create a QMainWindow in Designer with a list view, and ensure that
the dragDropMode is set to DropOnly or DragDrop.
- Right click on the view and select "Promote to..."
- Type the class name, let's say "MyListView", and in the "Header
file" field type "myprogram" (the name you'd use if you were to import
the main python code file)
- Click "Add", then "Promote"
- save the ui file in the same directory the myprogram.py is
- And that's the only code you'll need, avoiding any eventFilter or
whatsoever:


class MyListView(QtWidgets.QListView):
      def dragEnterEvent(self, event):
            # to get a dropEvent,  both the dragEnterEvent and
            # dragMoveEvent (which is fired right after) have to  
            # be accepted!
            event.accept()
      def dragMoveEvent(self, event):
            event.accept()
      def dropEvent(self, event):
            print('Something has been dropped in here!')


class Window(QtWidgets.QMainWindow):
      def __init__(self):
            QtWidgets.QWidget.__init__(self)
            loadUi('mywindow.ui', self)

            # the list view (and its properties/methods) is available
as  
            # a direct attribute of the main class
        
    self.listView.setVerticalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOn)




Still considering the small naming "drawbacks" and path issues listed
before, this allows you to have some clean code, get simple and
logical references to all widgets and still implement custom widgets
in an easy way.
For example, you can add a QPushButton and implement its paintEvent
only, or a QLabel and allow it to react to mousePressEvent by sending
a custom signal.


A couple of considerations:
- Whenever you'll use a promoted widget, PyQt will "silently import"
the file set as the "header"; if you've some processing in those
files, they will be executed everytime an ui (and its promoted widget)
is loaded.
- Paths: loadUi() doesn't behave according to the path of the running
program, but from where it's loaded. I'm using cxFreeze to build
Windows and MacOS binaries for some projects and I had to create my
own loadUi function that builds and returns the ui object (I don't
need the actual ui object, I could've ignored that, but that's not the
point):


def loadUi(uiPath, widget):
      current = path.dirname(path.abspath(__file__))

      #fix for cx_freeze
      if current.endswith('\\library.zip\\myproject'):
            current = current.replace('\\library.zip', '')
      elif current.endswith('/library.zip/myproject'):
            current = current.replace('/library.zip', '')
      return uic.loadUi(path.join(current, uiPath), widget)



While you can ignore the ifs if you're not using similar building
systems, the path relocation is necessary, since uic will try to load
the file from the path the program is ran from, which is not good.

Hope this helps :-)


Maurizio





--  
È difficile avere una convinzione precisa quando si parla delle
ragioni del cuore. - "Sostiene Pereira", Antonio Tabucchi
http://www.jidesk.net [1]

















Links:
------
[1] http://www.jidesk.net/

[Attachment #5 (text/html)]

<html>
<head>
<style type="text/css">
body,p,td,div,span{
	font-size:14px;font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, \
Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI \
Symbol"; color: #212121; };
body p{
	margin:0px;
}
</style>
</head>
<body><div>@ Maurizio<br></div><div>Thank you so much for clearing the nodal in my \
brain. Beautiful music you make, btw. <br></div><div>Regards \
Hans<br></div><div><br></div><div><br></div><blockquote style="border:0;border-left: \
2px solid #22437f; padding:0px; margin:0px; padding-left:5px; margin-left: 5px; \
"><div dir="ltr"><div dir="ltr"><div dir="ltr"><div dir="ltr"><div dir="ltr"><div \
dir="ltr"><div dir="ltr"><div dir="ltr"><div dir="ltr"><div dir="ltr"><div \
dir="ltr"><div dir="ltr"><div dir="ltr"><div class="gmail_quote"><blockquote \
class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid \
rgb(204,204,204);padding-left:1ex"><div>Here the link to the SO Question mentioned in \
the mail below:</div><div><a target="_blank" class="blue" \
href="https://stackoverflow.com/questions/46515179/subclassing-of-widgets-which-are-lo \
aded-by-uic-loadui">https://stackoverflow.com/questions/46515179/subclassing-of-widgets-which-are-loaded-by-uic-loadui</a></div></blockquote><div><br></div><div>After \
many years of playing around with PyQt I've found "my" optimal setup for a good \
environment allowing simpler coding and integration with .ui files created within \
Designer. I'd also like to add that the documentation about this is not always clear, \
and it sometimes "makes sense" only whenever you've completely understood how Qt, \
PyQt and the whole GUI environment works.<br></div><div><br>Let me share how I \
usually work.</div><div><br></div><div>- All main windows (QMainWindow and QDialog, \
but QWidget too) are only saved to .ui files, and I load their ui through loadUi(). \
While "building" with pyuic might be better for various reasons (paths, mainly), \
working with plain raw ui files avoids confusion: sometimes (a lot of times, in my \
case, it can be simple fatigue or distraction after hours of coding) you edit a \
widget in Designer and then you forget that you've to recreate the python ui file, \
then after minutes of trying to understand why something is not working as it should, \
you remember... This is annoying, and makes you lose a *lot* of time.</div><div>- Due \
to the previous point, all windows that use an .ui file only have to inherit from \
their base Qt class; the only drawback is that you've to be careful to never use \
object names that might conflict with python naming standards and QWidget/QObject \
property/function names: for example, "style", "cursor" or "layout". The huge \
advantage is that you don't need to refer to the "self.ui", and everything is \
transparently available as a property/method of the main widget class.</div><div>- \
All custom widgets of a GUI loaded from an .ui file that require some sort of \
customization that is not a public function or cannot be easily "fixed" through an \
eventFilter are "promoted widgets".</div><div><br></div><div>The last point is \
probably the one that creates more confusion above everything else. But, while it \
might seem an annoying thing to do, once you've got the hand of it, it's fairly easy \
to implement a widget just by subclassing only what you need.<br><br>Let's assume \
you've a QMainWindow with a QListView for which you only need to print out drop \
events, and let's assume you'll use "myprogram.py" as the file for your python \
program.</div><div><br></div><div>- Create a QMainWindow in Designer with a list \
view, and ensure that the dragDropMode is set to DropOnly or DragDrop.</div><div>- \
Right click on the view and select "Promote to..."</div><div>- Type the class name, \
let's say "MyListView", and in the "Header file" field type "myprogram" (the name \
you'd use if you were to import the main python code file)</div><div>- Click "Add", \
then "Promote"</div><div>- save the ui file in the same directory the myprogram.py \
is</div><div>- And that's the only code you'll need, avoiding any eventFilter or \
whatsoever:</div><div><br></div><div><div><font face="monospace, monospace">class \
MyListView(QtWidgets.QListView):</font></div><div><font face="monospace, \
monospace">&nbsp; &nbsp; def dragEnterEvent(self, event):</font></div><div><font \
face="monospace, monospace">&nbsp; &nbsp; &nbsp; &nbsp; # to get a \
dropEvent,&nbsp;</font><span style="font-family:monospace,monospace">both the \
dragEnterEvent and</span></div><div><font face="monospace, monospace">&nbsp; &nbsp; \
&nbsp; &nbsp; # dragMoveEvent (which is fired right after) have \
to&nbsp;</font></div><div><font face="monospace, monospace">&nbsp; &nbsp; &nbsp; \
&nbsp; # be accepted!</font></div><div><font face="monospace, monospace">&nbsp; \
&nbsp; &nbsp; &nbsp; event.accept()</font></div><div><font face="monospace, \
monospace">&nbsp; &nbsp; def dragMoveEvent(self, event):</font></div><div><font \
face="monospace, monospace">&nbsp; &nbsp; &nbsp; &nbsp; \
event.accept()</font></div><div><font face="monospace, monospace">&nbsp; &nbsp; def \
dropEvent(self, event):</font></div><div><font face="monospace, monospace">&nbsp; \
&nbsp; &nbsp; &nbsp; print('Something has been dropped in \
here!')</font></div><div><font face="monospace, \
monospace"><br></font></div><div><font face="monospace, monospace">class \
Window(QtWidgets.QMainWindow):</font></div><div><font face="monospace, \
monospace">&nbsp; &nbsp; def __init__(self):</font></div><div><font face="monospace, \
monospace">&nbsp; &nbsp; &nbsp; &nbsp; \
QtWidgets.QWidget.__init__(self)</font></div><div><font face="monospace, \
monospace">&nbsp; &nbsp; &nbsp; &nbsp; loadUi('mywindow.ui', \
self)</font></div></div><div><font face="monospace, monospace">&nbsp; &nbsp; &nbsp; \
&nbsp; # the list view (and its properties/methods) is available \
as&nbsp;</font></div><div><font face="monospace, monospace">&nbsp; &nbsp; &nbsp; \
&nbsp; # a direct attribute of the main class</font></div><div><font face="monospace, \
monospace">&nbsp; &nbsp; &nbsp; \
&nbsp;&nbsp;self.listView.setVerticalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOn)</font></div><div><br></div><div><br></div><div>Still \
considering the small naming "drawbacks" and path issues listed before, this allows \
you to have some clean code, get simple and logical references to all widgets and \
still implement custom widgets in an easy way.<br>For example, you can add a \
QPushButton and implement its paintEvent only, or a QLabel and allow it to react to \
mousePressEvent by sending a custom signal.<br><br></div><div>A couple of \
considerations:</div><div>- Whenever you'll use a promoted widget, PyQt will \
"silently import" the file set as the "header"; if you've some processing in those \
files, they will be executed everytime an ui (and its promoted widget) is \
loaded.</div><div>- Paths: loadUi() doesn't behave according to the path of the \
running program, but from where it's loaded. I'm using cxFreeze to build Windows and \
MacOS binaries for some projects and I had to create my own loadUi function that \
builds and returns the ui object (I don't need the actual ui object, I could've \
ignored that, but that's not the point):<br><br></div><div><div><font \
face="monospace, monospace">def loadUi(uiPath, widget):</font></div><div><span \
style="font-family:monospace,monospace">&nbsp; &nbsp; current = \
path.dirname(path.abspath(__file__))</span><br></div><div><font face="monospace, \
monospace">&nbsp; &nbsp; #fix for cx_freeze</font></div><div><font face="monospace, \
monospace">&nbsp; &nbsp; if \
current.endswith('\\library.zip\\myproject'):</font></div><div><font face="monospace, \
monospace">&nbsp; &nbsp; &nbsp; &nbsp; current = current.replace('\\library.zip', \
'')</font></div><div><font face="monospace, monospace">&nbsp; &nbsp; elif \
current.endswith('/library.zip/myproject'):</font></div><div><font face="monospace, \
monospace">&nbsp; &nbsp; &nbsp; &nbsp; current = current.replace('/library.zip', \
'')</font></div><div><font face="monospace, monospace">&nbsp; &nbsp; return \
uic.loadUi(path.join(current, uiPath), \
widget)</font></div></div><div><br></div><div>While you can ignore the ifs if you're \
not using similar building systems, the path relocation is necessary, since uic will \
try to load the file from the path the program is ran from, which is not \
good.</div><div><br>Hope this helps <img \
src="/groupoffice/views/Extjs3/themes/Default/images/emoticons/normal/smile.gif" \
alt=":-)"></div><div><br></div><div>Maurizio</div><div><br></div><div><br></div></div>--&nbsp;<br><div \
dir="ltr" class="gmail_signature">È difficile avere una convinzione precisa quando \
si parla delle ragioni del cuore. - "Sostiene Pereira", Antonio Tabucchi<br><a \
target="_blank" class="blue" \
href="http://www.jidesk.net/">http://www.jidesk.net</a></div></div></div></div></div></div></div></div></div></div></div></div></div></div>
 </blockquote></body></html>


[Attachment #6 (text/plain)]

_______________________________________________
PyQt mailing list    PyQt@riverbankcomputing.com
https://www.riverbankcomputing.com/mailman/listinfo/pyqt


[prev in list] [next in list] [prev in thread] [next in thread] 

Configure | About | News | Add a list | Sponsored by KoreLogic