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.


    Beginner Help On Tableview In UI Module

    Pythonista
    4
    12
    14495
    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.
    • ramvee
      ramvee last edited by ramvee

      Hi,
      I am unable to figure out, how to make user choose two tablecell values from different tables, and get these values out the function to process them further.
      Here i am able to get the values print to console from within the function. I just need them out as global variables i guess. Please help with simplest example. Thank you.
      Ps. I think Pythonista is an excellent app, but really wish the documentation on UI Module was more elaborate with examples :)
      Here is the script i am struggling with.. I actually need inputs from 4 such tables, i just put 2 tables here.

      # simple table
      import ui
      
      def cell_tapped1(sender):
          cellval1 = ds1.selected_row + 1
          print ('Maha', cellval1)
      tv1 = ui.TableView()
      tv1.frame = (0,0,95,300)
      tv1.width, tv1.height = 95, 270
      tv1.row_height = 30
      ds1 = ui.ListDataSource(['Sun','Moon','Mars','Rahu','Jupiter','Saturn','Mercury', 'Ketu','Venus' ])
      ds1.action = cell_tapped1
      tv1.data_source = tv1.delegate = ds1
      
      def cell_tapped2(sender):
          cellval2 = ds2.selected_row + 1
          print ('Antar',cellval2)
      tv2 = ui.TableView()
      tv2.frame = (95,0,95,300)
      tv2.width, tv2.height = 95, 270
      tv2.row_height = 30
      ds2 = ui.ListDataSource(['Sun','Moon','Mars','Rahu','Jupiter','Saturn','Mercury', 'Ketu','Venus' ])
      ds2.action = cell_tapped2
      tv2.data_source = tv2.delegate = ds2
      
      v = ui.View()
      v.name = 'Tables'
      v.background_color = "lightyellow"
      
      v.add_subview(tv1)
      v.add_subview(tv2)
      v.present('sheet')
      Phuket2 1 Reply Last reply Reply Quote 0
      • Phuket2
        Phuket2 @ramvee last edited by

        @ramvee , I have put an example below. I didn't do the exact easiest thing below, but in my opinion you need something like this pretty soon.
        So the idea is just to use a custom ui class. Will just help keep things together and work with the logic. Building Custom UI classes are well documented in the help file. They are very easy to understand and give you more control over your view.

        As far as controlling the users selection goes, I think the most would consider what most iOS apps do. Drill down. So you only ever have one list visible in the view at a time. Regardless you need some control over somethings. Eg, you could hide the titlebar and add a button to your view to dismiss it. Then you can do your own checks to see if you have a selection for each list. See ui.View.presents func parameters. When using custom ui views you get called back if a view is about to close, can also be helpful.

        Anyway, I hope the below is useful. I didn't try to rework all your code. Just give an example modifying your code. You are more than likely want to create your tables in the class also. You can see, I also pointed the delegate of tv1 to the custom class. Don't have to, but it makes it a little easier in this case to store results etc.

        # simple table
        import ui
        
        def cell_tapped1(sender):
            cellval1 = ds1.selected_row + 1
            print ('Maha', cellval1)
            
        tv1 = ui.TableView()
        tv1.frame = (0,0,95,300)
        tv1.width, tv1.height = 95, 270
        tv1.row_height = 30
        ds1 = ui.ListDataSource(['Sun','Moon','Mars','Rahu','Jupiter','Saturn','Mercury', 'Ketu','Venus' ])
        ds1.action = cell_tapped1
        tv1.data_source = tv1.delegate = ds1
        
        def cell_tapped2(sender):
            cellval2 = ds2.selected_row + 1
            print ('Antar',cellval2)
        tv2 = ui.TableView()
        tv2.frame = (95,0,95,300)
        tv2.width, tv2.height = 95, 270
        tv2.row_height = 30
        ds2 = ui.ListDataSource(['Sun','Moon','Mars','Rahu','Jupiter','Saturn','Mercury', 'Ketu','Venus' ])
        ds2.action = cell_tapped2
        tv2.data_source = tv2.delegate = ds2
        
        # Custom ui Class
        class MyClass(ui.View):
        	def __init__(self, *args, **kwargs):
        		super().__init__(*args, **kwargs)
        		self.table1_selection = None
        		self.bg_color = 'lightyellow'
        		self.make_view()
        		
        	def make_view(self):
        		self.add_subview(tv1)
        		self.add_subview(tv2)
        		tv1.data_source.action = self.tv1_action
        		
        	def tv1_action(self, sender):
        		self.table1_selection = sender.items[sender.selected_row]
        		print(self.table1_selection)
        		
        	# the ui module calls this method automatically, if its definded
        	# there are other callbacks you can see them in the help file 
        	def will_close(self):
        		print('view closing...Selection = ', self.table1_selection)
        		
        f=(0, 0, 300, 480)
        #v = ui.View(frame=f)
        v = MyClass(name='Tables', frame=f)
        #v.name = 'Tables'
        #v.background_color = "lightyellow"
        
        #v.add_subview(tv1)
        #v.add_subview(tv2)
        v.present('sheet')
        
        ramvee 1 Reply Last reply Reply Quote 0
        • ramvee
          ramvee @Phuket2 last edited by

          @Phuket2
          Hi,
          Thank you for your prompt help. The script really helped me. As per your suggestion I will read up more on building custom classes. If you can suggest a simple way i can the get values out of the will_close function, I can do further processing, because my actual program starts from these inputs.
          Ps. I have all your scripts posted in the forum, on my iPhone and printed out :). Thank you for all your help. I am finding programming using UI module very difficult.
          Ram

          Phuket2 2 Replies Last reply Reply Quote 0
          • Phuket2
            Phuket2 @ramvee last edited by Phuket2

            @ramvee , I at first also found the ui module difficult. But I soon realised it was for a number of reasons. Number 1 reason, I was very scared of it. Actually, nothing to be scared about. It really is well put together. I also didn't read enough. It does not take that long to read through the ui module help file. It's well worth doing.
            I would not say it's perfect, but I would still say it's fantastic.

            Also searching the forum is great. The built in search is not that great. But if you do a google site search on the forum it comes up with a lot better results.

            Getting the values out of the will_close is easy, as you can just access the values you have saved in your class. What's harder is to stop the view closing. Sorry, I just can't remember how to do it.

            Anyway, in my version below you hide ui title bar and create your own. Don't let it bother you, it's not that many lines. But you can see you have full control. Again, I have just edited the code from before. It's a very simplistic approach.

            One problem with trying to help you is that you can take many approaches to achieve the same result. Please don't think of this as the best way. It's just a way. When you experiment a little, you will see other ways, also other guys here might present other ideas.

            But ok, below is a updated version , I did not go for pretty. Eg, the finished button could have be an image etc...

            # simple table
            import ui, console
            
            def cell_tapped1(sender):
                cellval1 = ds1.selected_row + 1
                print ('Maha', cellval1)
                
            tv1 = ui.TableView()
            tv1.frame = (0,0,95,300)
            tv1.width, tv1.height = 95, 270
            tv1.row_height = 30
            ds1 = ui.ListDataSource(['Sun','Moon','Mars','Rahu','Jupiter','Saturn','Mercury', 'Ketu','Venus' ])
            ds1.action = cell_tapped1
            tv1.data_source = tv1.delegate = ds1
            
            def cell_tapped2(sender):
                cellval2 = ds2.selected_row + 1
                print ('Antar',cellval2)
            tv2 = ui.TableView()
            tv2.frame = (95,0,95,300)
            tv2.width, tv2.height = 95, 270
            tv2.row_height = 30
            ds2 = ui.ListDataSource(['Sun','Moon','Mars','Rahu','Jupiter','Saturn','Mercury', 'Ketu','Venus' ])
            ds2.action = cell_tapped2
            tv2.data_source = tv2.delegate = ds2
            
            # Custom ui Class
            class MyClass(ui.View):
            	def __init__(self, *args, **kwargs):
            		super().__init__(*args, **kwargs)
            		self.table1_selection = None
            		self.bg_color = 'lightyellow'
            		self.make_view()
            		
            	def make_view(self):
            		self.add_subview(tv1)
            		self.add_subview(tv2)
            		
            		tv1.data_source.action = self.tv1_action
            		
            		# make something that looks like a menu bar
            		menu = ui.View(frame=(0, 0, self.bounds.width, 44))
            		menu.bg_color = 'cornflowerblue'
            		lb = ui.Label()
            		lb.text = self.name
            		lb.size_to_fit()
            		lb.center = menu.bounds.center()
            		menu.add_subview(lb)
            		self.add_subview(menu)
            		
            		# make a finished button
            		btn = ui.Button(name='finished', frame=(0, 0, 70, 32))
            		btn.title = 'Finished'
            		btn.border_width = .5
            		btn.corner_radius = 3
            		btn.tint_color = 'white'
            		btn.center = menu.bounds.center()
            		btn.x = 5
            		btn.action = self.finished
            		menu.add_subview(btn)
            		
            		# adjust the y of the tables
            		tv1.y = menu.height + 5
            		tv2.y = menu.height + 5
            		
            	def tv1_action(self, sender):
            		self.table1_selection = sender.items[sender.selected_row]
            		print(self.table1_selection)
            		
            	def finished(self, sender):
            		# here we can check some stuff and decide to close the view 
            		# or not. as an example, has been set. you can close the view
            		# until you have clicked on table1 at least once
            		if not self.table1_selection:
            			result = console.alert('please select from table 1 first')
            			
            		self.close()
            		
            	# the ui module calls this method automatically, if its definded
            	# there are other callbacks you can see them in the help file 
            	def will_close(self):
            		print('view closing...Selection = ', self.table1_selection)
            		
            f=(0, 0, 300, 480)
            #v = ui.View(frame=f)
            v = MyClass(name='Tables', frame=f)
            #v.name = 'Tables'
            #v.background_color = "lightyellow"
            
            #v.add_subview(tv1)
            #v.add_subview(tv2)
            
            # here we supress the title bar
            v.present('sheet', hide_title_bar = True)
            

            Edit: ps, as we are using a custom view now, it's not that hard to extend of view in a meaningful way. You can still do it without a custom ui class, but your code gets fragmented pretty quickly. That's my opinion anyway

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

              Another take...

              # Two simple tables
              
              import ui
              
              neighbors = 'Sun Moon Mars Rahu Jupiter Saturn Mercury Ketu Venus'.split()
              
              
              class TwoTablesView(ui.View):
                  def __init__(self, name='Two Tables', bg_color='lightyellow'):
                      self.name = name
                      self.bg_color = bg_color
                      self.user_data = {}
                      self.add_subview(self.make_table_view('Maha', (0, 0, 95, 300)))
                      self.add_subview(self.make_table_view('Antar', (95, 0, 95, 300)))
                      self.present()
              
                  def make_table_view(self, name, frame):
                      table_view = ui.TableView(name=name, frame=frame)
                      table_view.row_height = 30
                      data_source = ui.ListDataSource(neighbors)
                      data_source.name = name
                      data_source.action = self.table_action
                      table_view.data_source = table_view.delegate = data_source
                      return table_view
              
                  def table_action(self, sender):
                      self.user_data[sender.name] = sender.items[sender.selected_row]
              
                  def will_close(self):
                      print(self.user_data)
              
              
              TwoTablesView()
              
              1 Reply Last reply Reply Quote 2
              • ramvee
                ramvee last edited by ramvee

                Wow,
                Thank You, @Phuket2 And @ccc for your prompt help. All your various scripts on this forum and github, help beginners like me a lot. Both scripts work well!
                Hats Off To @ccc that was truly pythonic ! I regret not asking for help in this forum earlier.
                And @Phuket2 , I will take your advice to really study the UI Module Help Documentation. I just wish there were more examples in it.
                Grateful! Namaste _/_

                Phuket2 2 Replies Last reply Reply Quote 1
                • Phuket2
                  Phuket2 @ramvee last edited by

                  @ramvee , not sure if it's evident to you or not. But all* ui elements are sub classes of ui.View (there are a few exceptions, ui.ButonItem being one of them). But for the most part all the ui Elements are ui.Views.
                  So the below sample works. It's not that you really want to do it that way. But it helps you understand how these items are passed around so easily.
                  So a button or a table, for example, are subclassed from ui.View. Meaning they look like a ui.View to functions/Methods that require a ui.View as a param. I am not sure I am explaining it well, but it is an important thing to get your head around. One way to think is that basically a ui Element is just a ui.View that has extended functionality for its purpose.

                  Look there are a few exceptions, but not many. Unfortunately, the exceptions give me pause when writing this.

                  The below can be practical sometimes. But it's more just to show that a ui Element is subclassed from ui.View and can be used as such.

                  import ui
                  
                  f = (0, 0, 600, 800)
                  tbl = ui.TableView(frame=f, name='Table' )
                  tbl.data_source = ui.ListDataSource(items=range(40))
                  tbl.present('sheet', title_bar_color = 'teal')
                  
                  1 Reply Last reply Reply Quote 0
                  • cvp
                    cvp last edited by cvp

                    I didn't even know that. Shame on me.
                    Perhaps, I'll drink to forget my own limits.🤕

                    1 Reply Last reply Reply Quote 1
                    • Phuket2
                      Phuket2 @ramvee last edited by

                      @ramvee , the next thing you will be thinking about is how to place your tables inside your view. The below is a simple example of placing 4 ui.TableViews into a View. It's a Custom ui View, but a ui.View anyway.

                      But the thing that's important to note that this view, is size and orientation friendly. If you change the style = 'panel' or 'fullscreen' you notice that the tables are scaled correctly. Also when you change the orientation of you device. Its because the flex settings of each view/ui.Table are set. In this case 'tlwhbr'. Meaning preserve top,left,width,height,bottom,right relative.

                      Again, flex is documented in the ui Module.
                      There is also another way. I will make another example. Both are valid, just depends on you are doing. The next example will use a callback to the ui Custom Class called layout.

                      Anyway, play around with the num_tables var and the style param and when the style is 'sheet' mode change the w, h values in the main. Everything should adjust accordingly for screen size

                      # Pythonista Forum - @Phuket2
                      import ui
                      
                      class MyClass(ui.View):
                      	def __init__(self, *args, **kwargs):
                      		super().__init__(*args, **kwargs)
                      		self.make_view()
                      		
                      	def make_view(self):
                      		num_tables = 4
                      		for i in range(0, num_tables):
                      			tbl = ui.TableView(name=str(i))
                      			tbl.width = self.width / num_tables
                      			tbl.height = self.height
                      			tbl.x = tbl.width * i
                      			tbl.data_source = ui.ListDataSource(items=range(40))
                      			tbl.flex = 'tlwhbr'
                      			self.add_subview(tbl)
                      			
                      			
                      
                      if __name__ == '__main__':
                      	w, h = 600, 800
                      	f = (0, 0, w, h)
                      	style = 'sheet'
                      	
                      	mc = MyClass(frame=f, bg_color='white', name='Tables')
                      	mc.present(style=style, animated=False)
                      
                      1 Reply Last reply Reply Quote 0
                      • Phuket2
                        Phuket2 @ramvee last edited by Phuket2

                        @ramvee , ok below is using layout technique to position your views. Both ways, flex and layout have their merits. I think most would say if flex way suits your needs, then this would be preferred method. Other times you might find the layout method easier. Again, don't forget they are all just views. And views can have subviews. It seems a little confusing, but it's not really. So some views could be relying on flex for placement in ts view, but enclosing views could be using layout. Hmmmm.... sounds like double Dutch. It's sounds a lot harder than it actually is. If you play a little with the ui Designer, it may give you a better insight to subviews with in subviews. Keeping in mind a sub view is just a view that has a parent view. Again another thing worth understanding, subviews that is. There is not that much to understand really. But when you add a view to another view as a subview, the coordinates are based on its parents frame/bounds. Which is great. There is another thing. accessing a object via list notation. Look this is also documented. But it's important to understand that a ui.View is not a flat name space so to speak. You can use list notation to access named subview objects. But you can have many views being subviews of a view, in turn, their views can contain subviews and so on. Again, just hard to explain for me. But I would say again, don't let it scare you. It becomes pretty easy and you soon figure out, it's the way it should be.

                        I am trying my hardest not to confuse you. But sharing some of the things I had to get over when learning the ui Module. Get over these small speed bumps, then it will be easy going for you.

                        # Pythonista Forum - @Phuket2
                        import ui
                        
                        class MyClass(ui.View):
                        	def __init__(self, num_tables=4, *args, **kwargs):
                        		super().__init__(*args, **kwargs)
                        		self.make_view(num_tables)
                        		
                        	def make_view(self, num_tables):
                        		for i in range(0, num_tables):
                        			tbl = ui.TableView(name='tbl_' +str(i))
                        			#tbl.width = self.width / num_tables
                        			#tbl.height = self.height
                        			#tbl.x = tbl.width * i
                        			tbl.data_source = ui.ListDataSource(items=range(40))
                        			#tbl.flex = 'tlwhbr'
                        			self.add_subview(tbl)
                        			
                        	def layout(self):
                        		# Layout is called automatically by the ui Module, for Custom
                        		# ui.Views (aka, classes that subclass ui.View) is only called
                        		# when a views frame/bounds change.
                        		
                        		# get a list of tbls that are subviews. This case we only have
                        		# ui.TableViews as subviews, but we could also have others, such
                        		# as buttons, other ui.Views etc...
                        		tbls = [tbl for tbl in self.subviews if type(tbl) is ui.TableView]
                        		
                        		w = self.width / len(tbls)
                        		h = self.height
                        		
                        		for i, tbl in enumerate(tbls):
                        			tbl.width = w
                        			tbl.height = h
                        			tbl.x = i * w  
                        	
                        if __name__ == '__main__':
                        	w, h = 600, 800
                        	f = (0, 0, w, h)
                        	style = 'sheet'
                        	
                        	mc = MyClass(num_tables=6,frame=f, bg_color='white', name='Tables')
                        	mc.present(style=style, animated=False)
                        	
                        	# access the table by name
                        	print(mc['tbl_1'])
                        	print(mc['tbl_2'].data_source)
                        

                        Edit, you can see in the make_view we don't size or place objects. It's done in layout. We are just creating the objects

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

                          Thank You @Phuket2 , for all your help!
                          You made me understand flex properties very well :)
                          Your scripts with comments help me learn UI Elements. Realised I need to learn more about classes and magic methods to get further. On the job! :)

                          Phuket2 1 Reply Last reply Reply Quote 1
                          • Phuket2
                            Phuket2 @ramvee last edited by

                            @ramvee , I did make an error by referring to parent views. Technically it's correct, but the superview property is the parent view when it comes to ui.Views. Eg, you create a ui.View/element, the superview property will be None until you call the add_subview() method. But it would have been more correct to talk about superviews rather than a parent view.

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