⬆️ ⬇️

Extending the Kivy Framework with the XPopup Package (Part 1)

These funny little animals



Not so long ago, I was faced with the task in short deadlines to write a working prototype of a GUI application that, without an extra line of code, would be good friends with both Windows and OS X. The choice fell on the Kivy snake framework, which easily solved the above. And also, in the basic configuration had all the necessary tools for implementing the application.



Well ... almost all. Under the cut, I'll tell you what's wrong and how to overcome it.



Hedgehog Kiwi - a proud bird



The framework has a useful class, kivy.uix.popup.Popup, for implementing pop-up windows. I will not go into the details of what he can do - the article is not about that. Who is curious - by reference you can read the documentation of this class and its ancestor - kivy.uix.modalview.ModalView .



But there are nuances. Suppose you are faced with a trivial task - to display a text message in a pop-up window. Popup allows you to do this quite simply, in one line:

')

Popup(title='', content=Label(text='  ')).open() 


Let's complicate the task a bit - add a button, by clicking on which the pop-up window should close:



 layout = BoxLayout(orientation="vertical") layout.add_widget(Label(text='  ')) button = Button(text='') layout.add_widget(button) popup = Popup(title='', content=layout) button.bind(on_press=popup.dismiss) popup.open() 


Also nothing military, but not quite convenient for a regular MessageBox , right?



As a former Delphist, I have the bad habit of calling MessageBox on one line. And in some century, a bad habit has benefited - after a few dozen cups of coffee XPopup comes on the scene



The main thing is to stop in time



Harmless idea to simplify your life with pop-up messages eventually grew into a whole package, which was happy to be turned on by the development team in the framework extension package.



For comparison, the above task with a button is implemented as follows:



 XNotifyBase(title='  !', text='  ?', buttons=['', ' ', ' ']) 


But let's go in order. The class hierarchy of a package looks like this:



Popup





We create convenience



Note. This article will discuss the classes of notifications ( XNotifyBase and its descendants). More on the other classes - in the next article .



XNotification class



Pop-up window with title and text, no buttons. Its feature is the ability to automatically close after a specified number of seconds:



 XNotification(text='    3 ', show_time=3) 


If show_time is not specified, the window will be closed only by calling the .dismiss () method.



XMessage class



Analogue of the usual MessageBox , i.e. a window that has a title (title), a kind of message (text) and the "Ok" button. Example:



 XMessage(text=' ', title='') 


The standard button signature easily changes to any other:



 XMessage(text=' ', title='', buttons=['']) 


It also simply replaces the set of buttons displayed:



 XMessage(text=' ', title='', buttons=['', ' ']) 


How to handle a button click - will be discussed below.



Class xrorror



In fact - the same XMessage . The difference is that this class sets the default title (that is, you can leave out the title ):



 XError(text='    ') 


I do not like the standard title - we set our own:



 XError(text='    ', title='-   ...') 


In order not to constantly indicate the title , do the following:



 class MyError(XError): buttons = ListProperty(['']) title = StringProperty('-   ...') MyError(text='    ') 


XConfirmation class



A pop-up window with the title “Confirmation” and the buttons “Yes” and “No”. It is convenient to use in cases where it is necessary to obtain confirmation (“Yes”) of an action or prohibition (“No”) from the user to perform this action.



First we need a handler for the event of closing the dialog:



 def my_callback(instance): #   XConfirmation,  True,     "Yes" if instance.is_confirmed(): print(' ') else: print(' ') 


After the handler is written, you can create a pop-up window:



 XConfirmation(text='  .  ?', on_dismiss=my_callback) 


Again, you can replace the standard buttons with your own. But in this case, the .is_confirmed () method will stop working, since it focuses on pressing the “Yes” button. This is easily solved by using the .button_pressed property, which stores the name of the pressed button. We make changes to our handler:



 def my_callback(instance): #     XBase if instance.button_pressed == '': print(' ') else: print(' ') 


Now you can safely create a window with your own set of buttons:



 XConfirmation( text='  .  ?', on_dismiss=my_callback, buttons=['', '']) 


XProgress class



A pop-up window with a progress indicator and a “Cancel” button (header and message are included). To control the indicator we will use the following properties:





Example:



 popup = XProgress(value=100, max=1000, text='  ...', title='', buttons=[]) 


This code will display a pop-up window without buttons, with 10% of the progress made. Further change in progress is possible in two ways.



Method 1 is using the .value property:



 #      popup.value = 20 


Method 2 — use the .inc () method:



 #     1  popup.inc() #     10  popup.inc(10) 


The peculiarity of using the .inc () method is that when the maximum value of progress is reached, the indicator does not stop at the maximum, but a “looping” occurs, i.e. Progress is reset and the countdown starts from scratch.



Example:



 #     90%  popup = XProgress(value=90, text='  ...', title='') #  15 -    5% popup.inc(15) 


This method is very useful in cases where the maximum or the number of iterations performed is not known in advance.



Along with the .inc () method, the .complete () method will be useful. This method does the following:





Class XNotifyBase



The above classes may not be enough for all occasions. It does not matter - we take XNotifyBase as a basis and draw everything your heart desires. This class gives the object the following behavior:





The .buttons property is inherited from the XBase ancestor, but more on that later.



Using the available properties, you can create your own single-use notification:



 XNotifyBase(title='  !', text='  ?', buttons=['', ' ', ' ']) 


or for multiple:



 class NotifyNewMail(XNotifyBase): buttons = ListProperty(['', ' ', ' ']) title = StringProperty('  !') text = StringProperty('  ?') popup = NotifyNewMail() 


It remains to describe your handler for the event of closing the dialog - and you can enjoy the result.



Afterword



A visual aid (video demonstration) can be viewed here .

Download XPopup package - here .



Enjoy all coding.

Source: https://habr.com/ru/post/301712/



All Articles