Skip to content

Commit 0b8955b

Browse files
committed
A new example from @Chrispizzi75 .
1 parent 580bbba commit 0b8955b

4 files changed

Lines changed: 1115 additions & 0 deletions

File tree

Lines changed: 286 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,286 @@
1+
# This my first app done using REMI and Python. Probably there is a better way to do it.
2+
# This app is a simple scoreboard. I use it when I play pool/biliard.
3+
# In the app is possible set-up how many Games one has to win, to win a Match.
4+
# Example: the program starts with 5 games to win for a match. The background color of the window of each player is normally green, when one player arrives
5+
# to 4 games won his background becomes orange (it's a sign that he needs only one more game to win the match). When you arrive to 5 your background
6+
# becomes red for 3 seconds and then it goes back to green, the games score goes back to 0 and your "matches won" increase of one.
7+
8+
import remi.gui as gui
9+
from remi import start, App
10+
import os
11+
import time
12+
import threading
13+
14+
class MyApp(App):
15+
16+
# I modified the original CSS file adding a "Button:hover" property and other color schemes; the main configuraton of the program has been done directly in the code.
17+
# Add the new CSS file in a /RES folder.
18+
def __init__(self, *args):
19+
res_path = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'res')
20+
super(MyApp, self).__init__(*args, static_file_path=res_path)
21+
22+
23+
def idle(self):
24+
pass
25+
26+
# This is the function called as a new thread that updates the Number displayed, change the background color to red for 3 seconds, reset the game variables,
27+
# change the background color back to green.
28+
def ChangeColor(self, Text, Side, Num, BtUp, BtDn):
29+
self.In = 1
30+
with self.update_lock:
31+
Text.set_text(Num)
32+
Side.style['background-color'] = 'red'
33+
BtUp.attributes['class']='up80red'
34+
BtDn.attributes['class']='dn80red'
35+
time.sleep(3) # I tried to make this function without use the thread but the "sleep" here frozen the interface update and I wasn't able to change
36+
# the background to red. Remi's guys helped me to solve this.
37+
with self.update_lock:
38+
Side.style['background-color'] = 'green'
39+
BtUp.attributes['class']='up80'
40+
BtDn.attributes['class']='dn80'
41+
self.LeftNum = 0
42+
self.RightNum = 0
43+
self.In = 0
44+
self.check_score()
45+
46+
def main(self):
47+
self.In = 0 # Used to disable all buttons when in thread function, otherwise strange things happen if you press a button when the app is in the thread
48+
self.LeftNum = 0 # Left player game won
49+
self.RightNum = 0 # Right player game won
50+
self.MatchNum = 5 # Number of game to win for each match
51+
self.LeftMatchNum = 0 # Left player match won
52+
self.RightMatchNum = 0 # Right player match won
53+
self.Name1 = 'LEFT' # Name left player
54+
self.Name2 = 'RIGHT' # Name right player
55+
56+
57+
# Main container configuration page
58+
widMenu = gui.Widget(width=480, height=610, layout_orientation=gui.Widget.LAYOUT_VERTICAL, style={'margin':'0px auto', 'background':'black'})
59+
# Configuration menu
60+
self.lblMenu = gui.Label('SCOREBOARD', width='100%', height='45px', style={'margin':'0px 0px 0px', 'padding-top':'10px', 'font-size':'40px', 'font-weight':'bold', 'color':'green', 'line-height':'45px', 'text-align':'center'})
61+
self.lblMenu2 = gui.Label('Setup players name:', width='100%', height='45px', style={'margin':'0px 0px 0px', 'padding-top':'10px', 'font-size':'30px', 'font-weight':'bold', 'line-height':'45px', 'text-align':'left'})
62+
self.lblName1 = gui.Label('PLAYER 1 NAME:', width='100%', height='35px', style={'margin':'0px 0px 0px', 'padding-top':'20px', 'font-size':'20px', 'line-height':'25px', 'text-align':'left'})
63+
self.txtName1 = gui.TextInput(width='96%', height='35px', style={'margin':'0px auto', 'padding-top':'20px', 'padding-left':'5px', 'font-size':'30px', 'line-height':'20px', 'text-align':'left', 'border':'1px solid white', 'background':'black'})
64+
self.txtName1.set_text('P1')
65+
self.lblName2 = gui.Label('PLAYER 2 NAME:', width='100%', height='35px', style={'margin':'0px 0px 0px', 'padding-top':'20px', 'font-size':'20px', 'line-height':'25px', 'text-align':'left'})
66+
self.txtName2 = gui.TextInput(width='96%', height='35px', style={'margin':'0px auto', 'padding-top':'20px', 'padding-left':'5px', 'font-size':'30px', 'line-height':'20px', 'text-align':'left', 'border':'1px solid white', 'background':'black'})
67+
self.txtName2.set_text('P2')
68+
## self.lblMatchSet = gui.Label('RACE TO:', width='100%', height='35px', style={'margin':'0px 0px 0px', 'padding-top':'20px', 'font-size':'20px', 'line-height':'25px', 'text-align':'left'})
69+
## self.txtMatchSet = gui.TextInput(width='100%', height='35px', style={'margin':'0px 0px 0px', 'padding-top':'20px', 'font-size':'30px', 'line-height':'20px', 'text-align':'left', 'border':'1px solid white', 'background':'black'})
70+
## self.txtMatchSet.set_text('5')
71+
# Start button
72+
btMenu = gui.Button('START', width='40%', height='40px', style={'margin':'50px 20% 20px', 'font-size':'30px', 'line-height':'30px', 'text-align':'center'})
73+
## widMenu.append([self.lblMenu, self.lblMenu2, self.lblName1, self.txtName1, self.lblName2, self.txtName2, self.lblMatchSet, self.txtMatchSet, btMenu])
74+
widMenu.append([self.lblMenu, self.lblMenu2, self.lblName1, self.txtName1, self.lblName2, self.txtName2, btMenu])
75+
# Buttons function call
76+
btMenu.onclick.connect(self.on_button_pressed_menu)
77+
78+
79+
# Main container scoreboard page
80+
wid = gui.Widget(width=480, height=610, style={'margin':'0px auto', 'background':'black'})
81+
# Title
82+
self.lbl = gui.Label('SCOREBOARD', width='100%', height='35px', style={'margin':'0px 0px 0px', 'padding-top':'10px', 'font-size':'30px', 'line-height':'35px', 'text-align':'center'})
83+
# Containers for games counters
84+
# Horizontal container
85+
wid1 = gui.Widget(width='100%', height=600, layout_orientation=gui.Widget.LAYOUT_HORIZONTAL, style={'background':'black'})
86+
# Container for left side
87+
self.wid2 = gui.Widget(width=230, height=350, margin='5px', style={'background':'green'})
88+
# Container for right side
89+
self.wid3 = gui.Widget(width=230, height=350, margin='5px', style={'background':'green'})
90+
# Left side interface
91+
self.lblLeftName = gui.Label(self.Name1, width='95%', height='60px', style={'margin':'20px 2px 0px', 'font-size':'40px', 'line-height':'60px', 'text-align':'center', 'overflow':'hidden'})
92+
self.lblLeftNum = gui.Label(self.LeftNum, width='100%', height='130px', style={'margin':'0px 0px 10px', 'font-size':'140px', 'line-height':'130px', 'text-align':'center'})
93+
self.btLeftPlus = gui.Button('', width='80px', height='80px', style={'margin':'0px 10px 20px', 'font-size':'50px', 'line-height':'50px', 'text-align':'center'})
94+
self.btLeftPlus.attributes['class']='up80'
95+
self.btLeftMinus = gui.Button('', width='80px', height='80px', style={'margin':'0px 10px 20px', 'font-size':'50px', 'line-height':'50px', 'text-align':'center'})
96+
self.btLeftMinus.attributes['class']='dn80'
97+
lblLeftMatch = gui.Label('MATCHES WON:', width=150, height='30px', style={'margin':'0px 5px', 'font-size':'20px', 'line-height':'30px', 'text-align':'left', 'display':'inline'})
98+
self.lblLeftMatches = gui.Label(self.LeftMatchNum, width=30, height='30px', style={'margin':'0px 5px', 'font-size':'20px', 'line-height':'30px', 'text-align':'left', 'display':'inline'})
99+
# Right side interface
100+
self.lblRightName = gui.Label(self.Name2, width='95%', height='60px', style={'margin':'20px 2px 0px', 'font-size':'40px', 'line-height':'60px', 'text-align':'center', 'overflow':'hidden'})
101+
self.lblRightNum = gui.Label(self.LeftNum, width='100%', height='130px', style={'margin':'0px 0px 10px', 'font-size':'140px', 'line-height':'130px', 'text-align':'center'})
102+
self.btRightPlus = gui.Button('', width='80px', height='80px', style={'margin':'0px 10px 20px', 'font-size':'50px', 'line-height':'50px', 'text-align':'center'})
103+
self.btRightPlus.attributes['class']='up80'
104+
self.btRightMinus = gui.Button('', width='80px', height='80px', style={'margin':'0px 10px 20px', 'font-size':'50px', 'line-height':'50px', 'text-align':'center'})
105+
self.btRightMinus.attributes['class']='dn80'
106+
lblRightMatch = gui.Label('MATCHES WON:', width=150, height='30px', style={'margin':'0px 5px', 'font-size':'20px', 'line-height':'30px', 'text-align':'left', 'display':'inline'})
107+
self.lblRightMatches = gui.Label(self.RightMatchNum, width=30, height='30px', style={'margin':'0px 5px', 'font-size':'20px', 'line-height':'30px', 'text-align':'left', 'display':'inline'})
108+
# Appends all the widgets to create the interface
109+
self.wid2.append([self.lblLeftName, self.lblLeftNum, self.btLeftPlus, self.btLeftMinus, lblLeftMatch, self.lblLeftMatches])
110+
self.wid3.append([self.lblRightName, self.lblRightNum, self.btRightPlus, self.btRightMinus, lblRightMatch, self.lblRightMatches])
111+
wid1.append(self.wid2)
112+
wid1.append(self.wid3)
113+
# Extra labels and button to manage:
114+
# The number of games to win, to win a match
115+
lblMatch = gui.Label('GAMES FOR MATCH:', width='50%', height='50px', style={'margin':'15px 2px 0px 10px', 'font-size':'25px', 'line-height':'35px', 'text-align':'center'})
116+
self.lblMatches = gui.Label(self.MatchNum, width='8%', height='50px', style={'margin':'15px 2px 0px', 'font-size':'25px', 'line-height':'35px', 'text-align':'center'})
117+
btMatchPlus = gui.Button('', width='50px', height='50px', style={'margin':'5px 2px 0px 20px', 'font-size':'30px', 'line-height':'30px', 'text-align':'center'})
118+
btMatchPlus.attributes['class']='up50'
119+
btMatchMinus = gui.Button('', width='50px', height='50px', style={'margin':'5px 2px', 'font-size':'30px', 'line-height':'30px', 'text-align':'center'})
120+
btMatchMinus.attributes['class']='dn50'
121+
wid1.append([lblMatch, btMatchPlus, self.lblMatches, btMatchMinus])
122+
# Reset buttons for Score and Matches won
123+
btReset = gui.Button('RESET SCORE', width='50%', height='35px', style={'margin':'10px 25% 10px', 'font-size':'25px', 'line-height':'30px', 'text-align':'center'})
124+
wid1.append(btReset)
125+
btResetMatch = gui.Button('RESET MATCH', width='50%', height='35px', style={'margin':'10px 25% 10px', 'font-size':'25px', 'line-height':'30px', 'text-align':'center'})
126+
wid1.append(btResetMatch)
127+
btSetting = gui.Button('SETTINGS', width='50%', height='35px', style={'margin':'10px 25% 20px', 'font-size':'25px', 'line-height':'30px', 'text-align':'center'})
128+
wid1.append(btSetting)
129+
# Buttons function call
130+
# 'LT', 'RT', 'PLUS', 'MINUS' are used to identify the button pressed; in this way I created a single function for Left and Right buttons.
131+
self.btLeftPlus.onclick.connect(self.on_button_pressed_plus, 'LT')
132+
self.btLeftMinus.onclick.connect(self.on_button_pressed_minus, 'LT')
133+
self.btRightPlus.onclick.connect(self.on_button_pressed_plus, 'RT')
134+
self.btRightMinus.onclick.connect(self.on_button_pressed_minus, 'RT')
135+
btMatchPlus.onclick.connect(self.on_button_pressed_match, 'PLUS')
136+
btMatchMinus.onclick.connect(self.on_button_pressed_match, 'MINUS')
137+
btReset.onclick.connect(self.on_button_pressed_reset)
138+
btResetMatch.onclick.connect(self.on_button_pressed_reset_match)
139+
btSetting.onclick.connect(self.on_button_setting)
140+
# Append the Titleand the interface to the main container
141+
wid.append(self.lbl)
142+
wid.append(wid1)
143+
144+
self.wid = wid
145+
self.widMenu = widMenu
146+
# Returning the configuration page
147+
return self.widMenu
148+
149+
#Used to change the size of the font based on the number of characters of the name
150+
@staticmethod
151+
def name_length(Name):
152+
if len(Name) <= 6:
153+
return (Name, 40)
154+
elif len(Name) <= 8:
155+
return (Name, 30)
156+
elif len(Name) <= 10:
157+
return (Name, 22)
158+
else:
159+
Name = Name[:14] #always cuts the name at 14 characters
160+
return (Name, 22)
161+
162+
#Used to setup the name typed in setting window in the scoreboard, and activate the main widget
163+
def on_button_pressed_menu(self, emitter):
164+
# left name
165+
Name = self.txtName1.get_text()
166+
Name, FntSize = MyApp.name_length(Name)
167+
FntSize = str(FntSize) + "px"
168+
self.lblLeftName.style['font-size'] = FntSize
169+
self.lblLeftName.set_text(Name)
170+
# right name
171+
Name = self.txtName2.get_text()
172+
Name, FntSize = MyApp.name_length(Name)
173+
FntSize = str(FntSize) + "px"
174+
self.lblRightName.style['font-size'] = FntSize
175+
self.lblRightName.set_text(Name)
176+
177+
## self.lblMatches.set_text(self.txtMatchSet.get_text())
178+
## self.MatchNum = int(self.txtMatchSet.get_text())
179+
self.set_root_widget(self.wid)
180+
181+
#Used to activate the setting widget
182+
def on_button_setting(self, emitter):
183+
self.set_root_widget(self.widMenu)
184+
185+
def check_score(self):
186+
# Here the software update automatically any number you can see in the app
187+
if (self.LeftNum < self.MatchNum) and (self.RightNum < self.MatchNum):
188+
self.lblLeftNum.set_text(self.LeftNum)
189+
self.lblRightNum.set_text(self.RightNum)
190+
self.lblLeftMatches.set_text(self.LeftMatchNum)
191+
self.lblRightMatches.set_text(self.RightMatchNum)
192+
self.lblMatches.set_text(self.MatchNum)
193+
# Here the software check if a background needs to be green or orange.
194+
if (self.LeftNum < self.MatchNum - 1):
195+
self.wid2.style['background-color'] = 'green'
196+
self.btLeftPlus.attributes['class']='up80'
197+
self.btLeftMinus.attributes['class']='dn80'
198+
if (self.RightNum < self.MatchNum - 1):
199+
self.wid3.style['background-color'] = 'green'
200+
self.btRightPlus.attributes['class']='up80'
201+
self.btRightMinus.attributes['class']='dn80'
202+
if (self.LeftNum == self.MatchNum - 1):
203+
self.wid2.style['background-color'] = 'orange'
204+
self.btLeftPlus.attributes['class']='up80org'
205+
self.btLeftMinus.attributes['class']='dn80org'
206+
if (self.RightNum == self.MatchNum - 1):
207+
self.wid3.style['background-color'] = 'orange'
208+
self.btRightPlus.attributes['class']='up80org'
209+
self.btRightMinus.attributes['class']='dn80org'
210+
# When one of the player win the match a thread is called to temporary convert the background to red and then move it back to green.
211+
# The thread is required to don't stop the automatic update of the graphics in the app.
212+
# The app passes to the thread three parameters: lblLeftNum (used as text field to show the number in the app), the widget where the information are on the interface,
213+
# LeftNum that is the varible to check the games won fro the left player). For right player is the same but instead of left in the varible I used right :-).
214+
215+
# Left side
216+
if (self.LeftNum >= self.MatchNum):
217+
Side = [self.lblLeftNum, self.wid2, self.LeftNum, self.btLeftPlus, self.btLeftMinus]
218+
t = threading.Thread(target=self.ChangeColor, args = (Side))
219+
t.start()
220+
self.LeftMatchNum = self.LeftMatchNum + 1
221+
# Right side
222+
elif (self.RightNum >= self.MatchNum):
223+
Side = [self.lblRightNum, self.wid3, self.RightNum, self.btRightPlus, self.btRightMinus]
224+
t = threading.Thread(target=self.ChangeColor, args = (Side))
225+
t.start()
226+
self.RightMatchNum = self.RightMatchNum + 1
227+
228+
# Each function use the Side parameter to identify who called the function and conseguently what update (maybe there is a different way to manage this).
229+
# Increase the number of the games won
230+
def on_button_pressed_plus(self, emitter, Side):
231+
if not self.In:
232+
if Side == 'LT':
233+
if self.LeftNum < self.MatchNum:
234+
self.LeftNum = self.LeftNum + 1
235+
elif Side == 'RT':
236+
if self.RightNum < self.MatchNum:
237+
self.RightNum = self.RightNum + 1
238+
self.check_score()
239+
240+
# Decrease the number of the games won
241+
def on_button_pressed_minus(self, emitter, Side):
242+
if not self.In:
243+
if Side == 'LT':
244+
if self.LeftNum != 0:
245+
self.LeftNum = self.LeftNum - 1
246+
elif Side == 'RT':
247+
if self.RightNum != 0:
248+
self.RightNum = self.RightNum - 1
249+
self.check_score()
250+
251+
# Increase or decrease the Matches number
252+
def on_button_pressed_match(self, emitter, Side):
253+
if not self.In:
254+
if Side == 'PLUS':
255+
self.MatchNum = self.MatchNum + 1
256+
elif Side == 'MINUS':
257+
# When the user decrease the number of Matches to win, in case this became lower than the actual games won by each player, automatically the number of games
258+
# won decrease too. It's a way to never have a number of games won bigger than the number of matches needed to win.
259+
# Try this in the app to better understand my explanation. With Match set-up to five, increase the game won of one player to three and then go down
260+
# with the Matches button to 1 and see what happen.
261+
if self.MatchNum > 1:
262+
if self.MatchNum - 1 <= self.LeftNum:
263+
self.LeftNum = self.LeftNum - 1
264+
if self.MatchNum - 1 <= self.RightNum:
265+
self.RightNum = self.RightNum - 1
266+
self.MatchNum = self.MatchNum - 1
267+
self.check_score()
268+
269+
def on_button_pressed_reset(self, emitter):
270+
if not self.In:
271+
self.LeftNum = 0
272+
self.RightNum = 0
273+
self.check_score()
274+
275+
def on_button_pressed_reset_match(self, emitter):
276+
if not self.In:
277+
self.LeftMatchNum = 0
278+
self.RightMatchNum = 0
279+
self.check_score()
280+
281+
282+
if __name__ == "__main__":
283+
# starts the webserver
284+
# optional parameters
285+
start(MyApp,address='', port=8081, multiple_instance=False,enable_file_cache=True, update_interval=0.1, start_browser=True)
286+
# start(MyApp, debug=True)
21.4 KB
Loading
48.7 KB
Loading

0 commit comments

Comments
 (0)