New To Anvil - Data Tables and Text Fields instead of Repeating Lists?

Okay, I know this is bare-bones beginner stuff for most of you, but I have scoured the forum and watched the tutorial videos several times. I am brand new to Python and Anvil, and I’m trying to learn my first programming language since C64 Basic. I can’t for the life of me figure out how to get a text field of some kind to display and allow changes to a piece of data from a data table. As in display a text box, where the user can type in a word or number and have it store into the data table to be retrieve later. Not a database, just a simple Anvil data table. The repeating list example does a semi-auto connection to the data table, but I can’t figure out how to use that knowledge for a group of individual textboxes…or even just one textbox, for that matter.

I’m starting to feel like my old brain isn’t cut out for modern programming - I just need a win. I’ve been trying for four days - can anyone give me an example to follow, and perhaps point me to a resource for more on this?

Thanks in advance for helping an old hobbyist out.

1 Like

Welcome to Anvil.

There are some concepts to pick up, but honestly, it’s not hard especially if you have programmed before (in any language).

I have knocked up a quick example for you. Click the link to clone the app into your IDE and see if that does what you want. The code is commented, and ask questions if you need to.

The auto connections are great to a point, but you’ll soon require more control so my example shows you how to save and fetch the data, and update the UI, by yourself.

https://anvil.works/build#clone:DH4KBOPXWDDDA4CT=HR26CVQG7ACEGEJETKUZ5TSA

2 Likes

Welcome!

There’s no reason to feel bad. Think of Anvil as an introduction to some super-powerful tools, all at your disposal. If it’s frustrating, I suspect it’s because there’s no clear path from where you left off (C64 Basic), to here. (Forest-for-the-trees syndrome.) I’m going to suggest a path, below.

Bear in mind, this is just my own personal take on my learning process. Each person is different, and builds connections their own way, from a different set of starting points. Ideas “click together”, for each of us, at their own pace.

Having programmed in many versions of Basic (including Commodore 64), I can see how Anvil’s world would be jarring. Many of the rules essential to programming in Basic are completely broken in Python. (No line numbers, for example.) That doesn’t mean that the language itself is broken, but that it “thinks” about many things in a very, very different way.

It’s a good way, though. :grinning: Far fewer shackles, far fewer details to get mired in, and many good ways you can organize things, when needed. Things that never existed in C64 Basic. As you get used to the climate, I think you’ll love it here!

The environment in which the language operates is also, conceptually, very different. In a C64, Basic essentially IS the computer. In Anvil, Python is operating inside someone else’s Web browser, inside a computer that may be half a world away. Anvil does an absolutely fantastic job of simplifying the whole mess, but it can’t fully hide all that.

So, you are tackling not only a different language (Python), but also all the layers built on top of it, at the top of which is Anvil. Even with Anvil, hiding most of the details, that is still a very long list of differences to digest all at once.

It’s not that you have an “old brain”. I’m over 60. I felt the same way, jumping into Java and its tooling and eco-system, all at once, a couple of years back. I failed. And that’s with a literal lifetime of programming experience, to shore me up. Too much detail, all at once, can mess anybody up.

So, how do you eat a programming elephant? One bite at a time.:smiley:

Fortunately, this subject is layered. And each layer stands on its own, so it can profitably be learned that way. Working one layer at a time lets me learn faster, because I’m much less distracted by all the parts that lie outside that layer.

So I would encourage you to start with the foundation of it all: the Python language itself, in isolation. No distractions.

For getting familiar with Anvil’s version of Python, on its own terms, may I suggest Skulpt? It’s the same Python, just working in your browser. It has its limits, but this would go nicely with many tutorials on Python v2.7.

Just a few no-pressure hours here can do a world of good. Tinker to your heart’s (and mind’s) content, just to see how things work, and how you can make things work. You can’t “break” anything, so try everything!

The next layer up is Python’s Standard Library: functions and classes that were created to work with Python. It make more things possible, or at least easier. A lot of it won’t make sense, until the foundations are clear, though, so tackle this when you decide you’re ready.

You don’t need to learn the whole Standard Library. It’s arranged in chunks, by topic. Just browse the chunks (modules) that seem interesting to you. Get the gist of what those parts offer to you.

The main point, often, is just that the Library is there, ready to support you. I’m a pro, and every day I still go back to the Library documentation, looking for easier ways to do things. There’s way too much in that Library for me to memorize. (Never mind the hundreds or thousands of additional libraries you can get, for various tasks.)

Anvil strongly leverages these standard layers. So, once you’re comfortable with those, Anvil’s ideas – and mechanics – will be substantially easier.

4 Likes

Hi.

I have had just done that in my small app I am working on. I will show you an example of simple adding rows from the template. (I might get back later to present searching, but sadly I must go soon)

I don’t know how to attach the app here for you to copy, but I can explain.

First I do have a form that will add a new toon to guild roster:

User can fill the information and then save (and there is the button to go back to the main form)

This the code that runs it:

class AddTask(AddTaskTemplate):
  def __init__(self, **properties):
    # Set Form properties and Data Bindings.
    self.init_components(**properties)

    # Any code you write here will run when the form opens.
    self.my_tasks = anvil.server.call('get_tasks')
    
  def sum_seconds(self, hours, minutes, seconds):
		"""This function will calculate sum of seconds when given hours, minutes and seconds"""
		h_multiplier = 3600
		m_multiplier = 60

		if self.text_box_AddTask_hours.text == None:
		  sum_hours = 0
		else:
		  sum_hours = int(hours)
		  
		if self.text_box_AddText_minutes.text == None:
		  sum_minutes = 0
		else:
		  sum_minutes = int(minutes)

		if self.text_box_AddText_seconds.text == None:
		  sum_seconds = 0
		else:
		  sum_seconds = int(seconds)
		  
		return sum_hours * h_multiplier + sum_minutes * m_multiplier + sum_seconds
   
   
    
  def button_AddTask_Save_click(self, **event_args):
    """This method is called when the button is clicked"""
    
    #TODO : Verify that task name is unique, if not alert and not save
    
    if self.text_box_AddTask_name.text == "":
      alert('You need to enter task name!')
      return
    
    else:
      self.my_tasks.add_row(task_Name= self.text_box_AddTask_name.text, \
                                      task_std_time= self.sum_seconds(self.text_box_AddTask_hours.text, \
                                                                      self.text_box_AddText_minutes.text, \
                                                                      self.text_box_AddText_seconds.text), \
                                      Visible= self.check_box_AddTask_visible.checked, \
                                      RecordMode= False
                           )
      
      anvil.open_form('AddTask')

  def button_1_click(self, **event_args):
    """This method is called when the button is clicked"""
    anvil.open_form('Main')

And this is the table:

So basically you name the text boxes, checkboxes and other objects, and then on your button tell to add a row with these values:

  def button_Add_click(self, **event_args):
    """This method is called when the button is clicked"""
       if self.text_box_name.text == "":
          alert('You need to enter task name!')
          return
        else:
          app_tables.guild_toons.add_row(Name= self.text_box_name.text, \
                                         Role= self.drop_down_role.selected_value, \
                                         Ready_to_ROCK= self.check_box_raid.checked)
        open_form('Form_Add')

Now about getting a result, but one record you want and populating other objects:

I have another form that will get a record by name

And this is an example way to have a button that populates objects (labels and a checkbox in this example) with values from a row. (For this one Name should be unique, or it will not work correctly)

from anvil import *
import anvil.tables as tables
import anvil.tables.query as q
from anvil.tables import app_tables

class Search(SearchTemplate):
  def __init__(self, **properties):
    # Set Form properties and Data Bindings.
    self.init_components(**properties)

    # Any code you write here will run when the form opens.
    

  def button_2_click(self, **event_args):
    """This method is called when the button is clicked"""
    open_form('Form_Add')

  def button_search_click(self, **event_args):
    """This method is called when the button is clicked"""
    if self.text_box_search_name.text == "":
      alert('You need to enter task name!')
      return
    else:
      toon = app_tables.guild_toons.get(Name= self.text_box_search_name.text)
      if toon == None:
        alert('There is no toon with this name!')
        return
      else:
        self.label_result_name.text = toon['Name']
        self.check_box_result_raid.checked = toon['Ready_to_ROCK']
        self.label_result_role.text = toon['Role']
        self.column_panel_result.visible = True  # this will make a panel that holds the labels and checkbox visible

So here we have a button that will get a row by its Name value, assign it to toon variable and then will populate labels and a checkbox with values from that particular row.

3 Likes

Thanks a lot, David! I now see a connection, and while I’m going to have to chew on this for a while to work the idea into my own project, it’s given me hope! I was going about it all wrong with trying to read a row into a variable and trying to access that - I could get it to output to the console but no further. I;m going to work on trying to get the data to auto-populate a text field if it’s already been entered for that “row”.

When I get my own version of this up and running, I’ll post it here so that others can see what you showed me and what I did with it. Thanks again!

1 Like

Piotr, somehow you knew exactly what I was looking for! I’m going to process your code around in my head and see what kind of connections I can make. Thanks for showing me the bones of it too - that’s how I’m going to learn!

1 Like

P.Colbert, that was probably the best pep talk I’ve had in years. I have to admit that I’ve watched programming languages evolve, and you’re right, losing the line numbers was a big thing! Everything effectively became a series of GOSUBs, if you will! There’s still a lot of concepts that I never learned over the years, but I think Python seems to have a fairly intuitive syntax. I just have to learn how to add on to some of the things I already know, and radically change other things. Initializations? I see it all the time…it’s on my mist of things to look up.

I’m going to check out this Skulpt you mentioned though…maybe if I can expand my knowledge of the underlying stuff (like initializations of things - part of a bigger thing, but I have no idea!) then maybe I’ll have a few new avenues to look for answers down when I hit a snag next time.

It’s good to see another…let’s say “seasoned user”…out here, too! You really seem to get what I was talking about, and that gives me more hope. Thanks a lot, man. I’m going exploring beyond my POKE 53280,X base!

Glad to be of service @fragholio!

If it’s any consolation, computing topics have grown and splintered so broadly, that no person can possibly grasp everything that’s (potentially) relevant to a piece of code. We’re all operating with various degrees of ignorance (and forgetfulness), 100% of the time, all day, every day. You’re in better company than you may realize! :grin:

One thing I’m glad to get rid of, from Basic, is global-scope variables: names that are visible everywhere in the program. In the GOSUB days, there really was no choice; these were the only variables you had! They were the only way we could get information into and out of subroutines.

But this created (and validated) a lot of baad habits. Any routine could step on (write to) any variable at any time. One misstep, and the wrong variable got the wrong value at the wrong time. The more complicated the program, the more variables you needed to keep thorough track of.

By contrast, in Python, every name is visible in only a very specific scope (range of lines). One routine usually can’t even see another routine’s internal names, much less alter their values, even intentionally.

Suddenly, to understand a routine, you don’t need to look, first, at every place it’s being invoked. Instead, you really can understand a single routine in isolation!

Understanding how scopes work – and how you can create your own – is central to understanding how Python code works.

Experimentation is really good for exploring this topic. For explaining it, the book “Learning Python” is a great resource.

Closely related to scopes is the meaning of names.

In Basic, a variable name not only identifies a value, it reserves storage space for that value. Got a different variable? It has its own independent value. The name also specifies the interpretation of that storage space. Is it a sequence of characters? A whole number? One that allows a fractional part? With few digits, or many? It’s all in the name. The name specifies the value’s type, i.e., what you can do with the value.

In Python, by contrast, values are typed, but names are not. A name simply refers to a value. There are a number of consequences to this, but Python makes really good use of all them.

For now, just know that many different names, in different places, can refer to that same value. The value, especially a really complex value, can outlive any of its names!

“Learning Python” covers fundamentals like these, and more. Like the Python Standard Library, the book is large, but don’t let that stop you. The way it’s organized, you can easily find and focus on just those parts you’re interested in.

Wow, C64, GOSUB… You old guys just POKEd my memory!

David, I’ve been looking through your code to see what concepts I need to work on to do my own stuff. First of all, your comments are VERY helpful! It’s really helped for me to get a “flow” of data through the program going in my brain. I’ve also been looking at each piece and looking up more on them. I’ve finally figured out what as “class” and “initialization” are - small things for most, but I feel like I’ve accomplished something! I think I may be doing it backward, but I’m learning this piece inside and out first, and then branch out from there.

These may be small and haphazard steps, but I’m making progress, thanks to you!

My pleasure.

I firmly believe if you’ve done any programming at all, you can pick up Python. I would recommend you find a simple Python course online (I can’t recommend one, maybe others can?).

But Google is your friend, coupled with Stack Overflow. Search and ask as you go. It’ll come quickly once you get the basic principles.

P.Colbert, thanks for helping turn my old concepts into something current and usable. Clearly things have gotten better as they became more…not complex, but…versatile? Varied? More ways to do more things?

I looked at that “Learning Python” book, but it’s $60 at my local bookstore, so I found “A Smarter Way to Learn Python” from Amazon based on a combination of cost and good reviews. I’m definitely using your Skulpt suggestion for the lessons on there and on another practice web site I found called DataQuest. Based on what you’ve mentioned so far, I’m going to take a step back and spend some time on relearning some of the fundamentals. Thanks a lot for giving me a shot of confidence to keep going forward with this!

Wholeheartedly agree, on all points.

Syntax is the easy part. It’s the stuff that you don’t find in the code – the underlying machine model – that’s often glossed over for newcomers.

Machine models vary greatly from language to language. But since they are ultimately what give the syntax actual meaning, I find it impractical to separate the two.

But the surrounding thought process is very similar, from one procedural language to the next. That really helps bridge a person from one to the next.

Glad to be able to help. If you like learning from others’ efforts, you might also try Reddit’s Python Education forum. I envy you, making these discoveries for yourself.

Many other languages (Basic included) force you to shoehorn your idea into their mold, and deal with many, many language-specific details. (Yes, .ASM, C, C++, Forth, and Lisp, I’m talking to you.)

Python, by comparison, is a breath of fresh air. By and large, it gets out of your way. (And then it dangles further opportunities off to the side…) Instead of having to focus on language-mandated details, you get to concentrate much more on your solution(s). And it has features that help you scale up, sensibly, as your solutions grow.

Easy to grow into. Hard to grow out of. I think you’ll have an absolute blast with it.:smile:

1 Like