All events lost when show() instead of doModal() is using
#1
Hello,

I've created my own progress control because I need two progress bars. For this I use the windowXMLDialog and run into courios behaviours. If I use windowXMLDialog.doModal() all events would be triggered (onAction, onClick etc.) but would lost when I use window.XMLDialog.show() instead.

Code:
CAPTION = 30401
PROCESS_LABEL = 30402
PROGRESS_1 = 30404
PROGRESS_TOTAL = 30405
CLOSE_BUTTON = 30406
CANCEL_DIALOG  = ( 7, 9, 10, 11, 92, 216, 247, 257, 275, 61467, 61448, )

class ProgressInfo(xbmcgui.WindowXMLDialog):

    def __init__( self, *args, **kwargs ):
            xbmcgui.WindowXML.__init__(self)

    def onInit( self ):
            print 'onInit triggered'
        self.initialize()

    def initialize(self):
            self.closeButton = self.getControl(CLOSE_BUTTON)
             self.getControl(CAPTION).setLabel(__getLS__(30005))
        self.getControl(PROCESS_LABEL).setLabel(__getLS__(30011))
        self.getControl(CLOSE_BUTTON).setLabel(__getLS__(30012))
                self.setProperty('isCanceled', 'False')
                
    def update(self, progress_1, progress_2, info):
            self.getControl(PROCESS_LABEL).setLabel(info)
            self.getControl(PROGRESS_1).setPercent(progress_1)
            self.getControl(PROGRESS_TOTAL).setPercent(progress_2)

    def onClick(self, controlId):
            print 'Control-ID: ' + str(controlId)
            self.setProperty('isCanceled', 'True')

    def onFocus(self, controlId):
        self.controlId = controlId

    def onAction(self, action):
        self.setProperty('isCanceled', 'True')
        print 'Action-ID: ' + str(action)
        if (action in CANCEL_DIALOG):
            self.close()

    def onControl(self, control):
        print "onControl triggered"

and here we go:

Code:
        progress = ProgressInfo( "script-Backup_Progress.xml" , __cwd__, "Default")
                progress.show()
                progress.initialize()
            #progress.doModal()
            while not progress.getProperty('isCanceled') == 'True':
                        # do some operations and update progressbars
                                # setProperty('isCanceled', 'True') if all operations are done
                        time.sleep(1)
                  progress.close()
                  del progress

I need .show() instead of .doModal() otherwise the progress bars aren't updated. But I lost any interaction with the window and I can't close it. Why?

_BJ1
Reply
#2
Hmm,

- anyone else?
- too simple?
- perhaps a bug?
- or I'm stupid?
Reply
#3
Show gives you a modeless window (no events). DoModal gives you a modal window (has events).
Always read the XBMC online-manual, FAQ and search the forum before posting.
Do not e-mail XBMC-Team members directly asking for support. Read/follow the forum rules.
For troubleshooting and bug reporting please make sure you read this first.


Image
Reply
#4
Thank you for the reply. So is .show useless and also senseless. Not as good because I had to implement my behaviours inside the class...

_BJ1
Reply
#5
I know that it is old post, but I've been looking to implement something similar.

In my case it is simple custom dialog progress. It will be like xbmcgui.dialogprogress(), but with additional button.

But, I am getting the same problem. If I use doModal() the buttons works, but I lose the ability to modify in progress bar from my python code. If I use show(), I can modify the progress bar from my code, but the button actions disappear.

Both cases, it doesn't have the same behaviour of the xbmcgui.dialogprogress(), there the progress can be modified and the button action works.

Is it way to do that?

There is a limitation in code?

Will it be implemented?

I've tried using threads to call the doModal(), but it doesn't work neither Sad

Thanks in advance.
Reply
#6
I don't know about xml-based GUI, but in Python-based GUI a window in modal mode can be updated from another thread. This does not apply to ControlProgress class because it is broken.

For xml-based GUI it should be the same: doModal in the main thread and updating from a secondary thread. Just don't forget to terminate the secondary thread when the work is done because in Kodi daemon flag does not work.
Reply
#7
just tested WindowXMLDialog with doModal() and see no issue controlling the progressbar...

Code:
prog = self.getControl(999)
prog.setPercent(10.0)
xbmc.sleep(1000)
prog.setPercent(20.0)

works fine here
Do not PM or e-mail Team-Kodi members directly asking for support.
Always read the Forum rules, Kodi online-manual, FAQ, Help and Search the forum before posting.
Reply
#8
1. You can't call in parallel thread only doModal. You need call whole class
2. You need callback for controlling called class.

Code:
xml = XML_FILE
    path = PATH

    # Thread
    class Thrd(threading.Thread):
        def __init__(self, t, *args):
            threading.Thread.__init__(self, target=t, args=args)
            self._stop = threading.Event()
            self.start()


    # XML dialog class
    class TestDlg(xbmcgui.WindowXMLDialog):
        def __init__(self, *args, **kwargs):

            # Run external function for getting TestDlg object (callback)
            kwargs['getself'](self)  

            xbmcgui.WindowXMLDialog.__init__(self)

        # Close on click        
        def onClick(self, controlID):
            self.close()
          
    # XML dialog External control class  
    class TestDlgCtrl():
        def __init__(self):

            # XML dialog object  
            self.ext_self = None
            # Call XML dialog class
            self.thrd = Thrd(self._start)
        
        # XML dialog class starter
        def _start(self):
            TestDlg(xml, path, getself=self.getself).doModal()
        
        # Function for getting XML dialog object, kwargs['getself'](self) in XML dialog class
        def getself(self, ext_self):
            self.ext_self = ext_self
        
        # Close XML dialog
        def close(self):
            self.ext_self.close()
            # Delete thread
            del self.thrd
    
    dlg = TestDlgCtrl()
    xbmc.sleep(500)
    dlg.close()
Reply
#9
(2016-12-18, 19:47)Roman_V_M Wrote: I don't know about xml-based GUI, but in Python-based GUI a window in modal mode can be updated from another thread. This does not apply to ControlProgress class because it is broken.

For xml-based GUI it should be the same: doModal in the main thread and updating from a secondary thread. Just don't forget to terminate the secondary thread when the work is done because in Kodi daemon flag does not work.
I think, I tried that. But, it could be I didn't do properly. I will try again. Thank you.
Reply
#10
(2016-12-18, 20:26)ronie Wrote: just tested WindowXMLDialog with doModal() and see no issue controlling the progressbar...

Code:
prog = self.getControl(999)
prog.setPercent(10.0)
xbmc.sleep(1000)
prog.setPercent(20.0)

works fine here
The issue is not with the WindowXMLDialog. The progressbar works perfect. The problem is using xbmcgui.WindowDialog instead. The progressbar control doesn't appear. I've tried with other controls and it works well.
Reply
#11
(2016-12-19, 10:52)Taifxx Wrote: 1. You can't call in parallel thread only doModal. You need call whole class
2. You need callback for controlling called class.
Ok I will give it a try.

Any case my current code is:
Reply
#12
Code:
<?xml version="1.0" encoding="UTF-8"?>
<window type="dialog">
    <!-- 1280 x 720 -->
    <defaultcontrol always="true">32503</defaultcontrol>
    <include>dialogeffect</include>
    <depth>DepthDialog+</depth>
    <controls>
        <control type="image">
            <!-- Background -->
            <posx>320</posx>
            <posy>230</posy>
            <width>640</width>
            <height>250</height>
            <texture>Bg/black.png</texture>
        </control>
        <control type="image">
            <!-- Background Title -->
            <posx>320</posx>
            <posy>230</posy>
            <width>640</width>
            <height>48</height>
            <texture>Bg/blue.png</texture>
        </control>
        <control type="label" id="32510">
            <!-- Title -->
            <label>[B]Quasar[/B]</label>
            <posx>350</posx>
            <posy>230</posy>
            <width>640</width>
            <height>48</height>
            <font>font14</font>
            <align>left</align>
            <aligny>center</aligny>
            <textcolor>white</textcolor>
            <shadowcolor>AA000000</shadowcolor>
        </control>
        <control type="label" id="32511">
            <!-- Line 1 -->
            <posx>340</posx>
            <posy>290</posy>
            <width>575</width>
            <height>17</height>
            <align>left</align>
            <aligny>center</aligny>
            <textcolor>silver</textcolor>
            <shadowcolor>AA000000</shadowcolor>
        </control>
        <control type="label" id="32512">
            <!-- Line 2 -->
            <posx>340</posx>
            <posy>315</posy>
            <width>575</width>
            <height>17</height>
            <align>left</align>
            <aligny>center</aligny>
            <textcolor>silver</textcolor>
            <shadowcolor>AA000000</shadowcolor>
        </control>
        <control type="label" id="32513">
            <!-- Line 3 -->
            <posx>340</posx>
            <posy>340</posy>
            <width>575</width>
            <height>17</height>
            <align>left</align>
            <aligny>center</aligny>
            <textcolor>silver</textcolor>
            <shadowcolor>AA000000</shadowcolor>
        </control>
        <control type="button" id="32520">
            <description>Left Button</description>
            <label>[B]Download in background[/B]</label>
            <posx>380</posx>
            <posy>420</posy>
            <width>220</width>
            <height>40</height>
            <font>font10</font>
            <align>center</align>
            <textoffsetx>10</textoffsetx>
            <texturenofocus>Bg/button.png</texturenofocus>
            <texturefocus>Bg/blue.png</texturefocus>
            <enabled>true</enabled>
        </control>
        <control type="button" id="32521">
            <description>Right Button</description>
            <label>[B]Stop buffering[/B]</label>
            <posx>650</posx>
            <posy>420</posy>
            <width>220</width>
            <height>40</height>
            <font>font10</font>
            <align>center</align>
            <textoffsetx>10</textoffsetx>
            <texturenofocus>Bg/button.png</texturenofocus>
            <texturefocus>Bg/blue.png</texturefocus>
            <enabled>true</enabled>
        </control>
        <control type="progress" id="32525">
            <description>progress control</description>
            <posx>350</posx>
            <posy>390</posy>
            <width>580</width>
            <height>16</height>
            <visible>true</visible>
        </control>
    </controls>
</window>
Reply
#13
Code:
import xbmcaddon
import xbmcgui

# Constants
ACTION_MOVE_LEFT = 1
ACTION_MOVE_RIGHT = 2


class DialogBuffering(xbmcgui.WindowXMLDialog):
    """
    Dialog Buffering class
    return ret=> -1 = no selection, 0 = download in background, 1 = stopping
    """

    def __init__(self, *args, **kwargs):
        xbmcgui.WindowXML.__init__(self, *args)
        self.line1 = kwargs.get('line1', '')
        self.line2 = kwargs.get('line2', '')
        self.line3 = kwargs.get('line3', '')
        self.ret = -1
        self.thread = None
        self.doModal()
        # here I've tried to call the modal as thread, it didn't work, I lose the buttons actions
        # self.thread = Thread(target=self.doModal)
        # self.thread.start()

    def onInit(self):
        """
        Creation of the dialog with the information from init
        """
        self.getControl(32511).setLabel(self.line1)
        self.getControl(32512).setLabel(self.line2)
        self.getControl(32513).setLabel(self.line3)
        self.getControl(32525).setPercent(0)

    def update(self, percent=0, line1=None, line2=None, line3=None):
        """
        Update's the progress dialog.
        :param percent: percent complete. (0:100)
        :type percent: integer
        :param line1: line #1 text.
        :type line1: str
        :param line2: line #2 text.
        :type line2: str
        :param line3: line #3 text.
        :type line3: str
        """
        self.line1 = line1
        self.line2 = line2
        self.line3 = line3
        self.getControl(32511).setLabel(self.line1)
        self.getControl(32512).setLabel(self.line2)
        self.getControl(32513).setLabel(self.line3)
        self.getControl(32525).setPercent(percent)

    def onClick(self, control_id):
        """
        On click
        :param control_id:
        """
        if control_id == 32520:
            # Download in background button
            self.ret = 0
            self.close()

        elif control_id == 32521:
            # stopping button
            self.ret = 1
            self.close()

    def onAction(self, action):
        """
        On action
        :param action: action linked to key
        """
        if action.getId() == ACTION_MOVE_LEFT:
            self.setFocusId(32520)
        if action.getId() == ACTION_MOVE_RIGHT:
            self.setFocusId(32521)


ADDON = xbmcaddon.Addon()
ADDON_PATH = ADDON.getAddonInfo("path")
window = DialogBuffering("DialogBuffering.xml", ADDON_PATH, "Default", title="Buffering Window",
                         line1='Buffering (1.05%) - 2.4 GB', line2='Downloading...',
                         line3='My file Title', left='Download in background',
                         right='Stop buffering')
# here I would like to be able to modify the progress
del window
Reply
#14
(2016-12-18, 19:47)Roman_V_M Wrote: I don't know about xml-based GUI, but in Python-based GUI a window in modal mode can be updated from another thread. This does not apply to ControlProgress class because it is broken.

For xml-based GUI it should be the same: doModal in the main thread and updating from a secondary thread. Just don't forget to terminate the secondary thread when the work is done because in Kodi daemon flag does not work.
I've done some tests and you are right. It is possible to update the control from second thread.
Code:
def onInit(self):
        """
        Creation of the dialog with the information from init
        """
        self.getControl(32511).setLabel(self.line1)
        self.getControl(32512).setLabel(self.line2)
        self.getControl(32513).setLabel(self.line3)
        self.getControl(32525).setPercent(0)
        self.thread = Thread(target=self.change)
        self.thread.start()

Code:
def change(self):
        for x in range(0, 100, 5):
            self.update(x, "Hello")
            time.sleep(0.5)
I am wondering how to do it from the main?

My goal is:

my_windows = BufferingWindow()

my_windows.update(10, "Hello")
sleep(1)
my_windows.update(90, "Hello")
sleep(1)
my_windows.update(100, "Hello")

my_windows.close()
del my_windows

PS/I didn't terminate properly the second thread. I need to add that to the code.
Reply
#15
I'm sorry. Forgot define Thrd:

Code:
class Thrd(threading.Thread):
    def __init__(self, t, *args):
        threading.Thread.__init__(self, target=t, args=args)
        self._stop = threading.Event()
        self.start()

Edited code in post
Reply

Logout Mark Read Team Forum Stats Members Help
All events lost when show() instead of doModal() is using0