omz:forum

    • Register
    • Login
    • Search
    • Recent
    • Popular

    Welcome!

    This is the community forum for my apps Pythonista and Editorial.

    For individual support questions, you can also send an email. If you have a very short question or just want to say hello — I'm @olemoritz on Twitter.


    Converting tkinter app to Pythonista UI

    Pythonista
    5
    7
    3132
    Loading More Posts
    • Oldest to Newest
    • Newest to Oldest
    • Most Votes
    Reply
    • Reply as topic
    Log in to reply
    This topic has been deleted. Only users with topic management privileges can see it.
    • ChrisHare
      ChrisHare last edited by

      So, I know I can't run tkinter in Pythonista. Not a big deal.

      I have a running tkinter app that I would like to convert to the UI class. I like the date picker, UT I have a data source I would like to display I something like the date picker. Is there a widget to do this or has someone built one already? The current tkinter app uses a drop down, which would be ok, but I would prefer the date picker style.

      cvp 1 Reply Last reply Reply Quote 0
      • cvp
        cvp @ChrisHare last edited by

        @ChrisHare Use ObjectiveC UIPickerView, see an example here

        It is an example with images, but, of course, you can do that with texts, like here

        # coding: utf-8
        
        from objc_util import ObjCInstance, c, ObjCClass, ns, create_objc_class, NSObject
        from ctypes import c_void_p
        import ui
        
        
        # Data for both pickers
        _data = [
            [str(x) for x in range(2000, 2040)],
            ['xxxx', 'yyyy', 'zzzz']
        ]
        
        # ObjC classes
        UIColor = ObjCClass('UIColor')
        UIPickerView = ObjCClass('UIPickerView')
        UIFont = ObjCClass('UIFont')
        NSAttributedString = ObjCClass('NSAttributedString')
        
        
        # Default attributes, no need to recreate them again and again
        def _str_symbol(name):
            return ObjCInstance(c_void_p.in_dll(c, name))
        
        
        _default_attributes = {
            _str_symbol('NSFontAttributeName'): UIFont.fontWithName_size_(ns('Courier'), 16),
            _str_symbol('NSForegroundColorAttributeName'): UIColor.redColor(),
            _str_symbol('NSBackgroundColorAttributeName'): UIColor.greenColor()
        }
        
        
        # Data source & delegate methods
        def pickerView_attributedTitleForRow_forComponent_(self, cmd, picker_view, row, component):
            tag = ObjCInstance(picker_view).tag()
            return NSAttributedString.alloc().initWithString_attributes_(ns(_data[tag - 1][row]), ns(_default_attributes)).ptr
        
        
        def pickerView_titleForRow_forComponent_(self, cmd, picker_view, row, component):
            tag = ObjCInstance(picker_view).tag()
            return ns(_data[tag - 1][row]).ptr
        
        
        def pickerView_numberOfRowsInComponent_(self, cmd, picker_view, component):
            tag = ObjCInstance(picker_view).tag()
            return len(_data[tag - 1])
        
        
        def numberOfComponentsInPickerView_(self, cmd, picker_view):
            return 1
        
        
        def rowSize_forComponent_(self, cmd, picker_view, component):
            return 100
        
        
        def pickerView_rowHeightForComponent_(self, cmd, picker_view, component):
            return 30
        
        
        def pickerView_didSelectRow_inComponent_(self, cmd, picker_view, row, component):
            tag = ObjCInstance(picker_view).tag()
            print(f'Did select {_data[tag - 1][row]}')
        
        
        methods = [
            numberOfComponentsInPickerView_, pickerView_numberOfRowsInComponent_,
            rowSize_forComponent_, pickerView_rowHeightForComponent_, pickerView_attributedTitleForRow_forComponent_,
            pickerView_didSelectRow_inComponent_
        ]
        
        protocols = ['UIPickerViewDataSource', 'UIPickerViewDelegate']
        
        
        UIPickerViewDataSourceAndDelegate = create_objc_class(
            'UIPickerViewDataSourceAndDelegate', NSObject, methods=methods, protocols=protocols
        )
        
        
        # UIPickerView wrapper which behaves like ui.View (in terms of init, layout, ...)
        class UIPickerViewWrapper(ui.View):
            def __init__(self, **kwargs):
                super().__init__(**kwargs)
                self._picker_view = UIPickerView.alloc().initWithFrame_(ObjCInstance(self).bounds()).autorelease()
                ObjCInstance(self).addSubview_(self._picker_view)
        
            def layout(self):
                self._picker_view.frame = ObjCInstance(self).bounds()
        
            @property
            def tag(self):
                return self._picker_view.tag()
        
            @tag.setter
            def tag(self, x):
                self._picker_view.setTag_(x)
        
            @property
            def delegate(self):
                return self._picker_view.delegate()
        
            @delegate.setter
            def delegate(self, x):
                self._picker_view.setDelegate_(x)
        
            @property
            def data_source(self):
                return self._picker_view.dataSource()
        
            @data_source.setter
            def data_source(self, x):
                self._picker_view.setDataSource_(x)
        
        
        class MyView(ui.View):
            def __init__(self, **kwargs):
                super().__init__(**kwargs)
        
                self.background_color = 'white'
        
                self.delegate_and_datasource = UIPickerViewDataSourceAndDelegate.alloc().init().autorelease()
        
                pv1 = UIPickerViewWrapper(frame=[100, 100, 200, 100])
                pv1.delegate = self.delegate_and_datasource
                pv1.data_source = self.delegate_and_datasource
                pv1.tag = 1
                self.add_subview(pv1)
        
                pv2 = UIPickerViewWrapper(frame=[100, 400, 200, 100])
                pv2.delegate = self.delegate_and_datasource
                pv2.data_source = self.delegate_and_datasource
                pv2.tag = 2
                self.add_subview(pv2)
        
        
        if __name__ == '__main__':
            v = MyView()
            v.present('full_screen')
        
        1 Reply Last reply Reply Quote 0
        • SmartGoat
          SmartGoat last edited by

          @cvp and is there a way to do the opposite, like using pyui files with tkinter for a desktop (Windows) program ?
          Cordially,
          SmartGoat

          cvp mikael 3 Replies Last reply Reply Quote 0
          • cvp
            cvp @SmartGoat last edited by

            @SmartGoat No idea at all, sorry

            1 Reply Last reply Reply Quote 0
            • mikael
              mikael @SmartGoat last edited by

              @SmartGoat, I would expect it to be feasible, as the Pythonista views are not overly exotic, but I do not think anyone has already built this for you.

              1 Reply Last reply Reply Quote 1
              • cvp
                cvp @SmartGoat last edited by cvp

                @SmartGoat rename a .pyui file into .txt and edit it, you will see it is only a dictionary of keywords, and you could easily read it and build an UI

                1 Reply Last reply Reply Quote 0
                • ccc
                  ccc last edited by

                  Even better to rename .pyui file to .json because that is what it is.

                  1 Reply Last reply Reply Quote 1
                  • First post
                    Last post
                  Powered by NodeBB Forums | Contributors