Front Office Football Central

Front Office Football Central (http://forums.operationsports.com/fofc//index.php)
-   Dynasty Reports (http://forums.operationsports.com/fofc//forumdisplay.php?f=8)
-   -   Groundhog learns Python - Road to a Basketball Text Sim (http://forums.operationsports.com/fofc//showthread.php?t=89021)

GoldenCrest Games 08-10-2016 07:52 AM

Quote:

Originally Posted by Groundhog (Post 3113645)
Most interesting thing has probably been how much I've adopted Python at work off the back of trying to make this thing - some of which has made my team's lives a lot easier (or at least, a lot less monotonous).


I've found the same thing. Since I started writing sports sims, I've been transferring the new programming skills to my job, writing various data crunching tools. (which has ended up helping career growth)

Funny how that works out!

nilodor 08-19-2016 03:05 PM

Silly noob question:

I'm trying to generate random numbers so I've done
Code:

from _random import Random

A = []
for i in range(0,8):
    A.append(4+Random().random())


But when I print A, I get the same random number the entire time. I'm kind of confused as to why as I thought if I don't specify a seed I should get a different random number based upon the system clock. Or is it just happening too fast, so the clock is the same?

nilodor 08-19-2016 03:22 PM

Quote:

Originally Posted by nilodor (Post 3115054)
Silly noob question:

I'm trying to generate random numbers so I've done
Code:

from _random import Random

A = []
for i in range(0,8):
    A.append(4+Random().random())


But when I print A, I get the same random number the entire time. I'm kind of confused as to why as I thought if I don't specify a seed I should get a different random number based upon the system clock. Or is it just happening too fast, so the clock is the same?


Apparently _random is different than random, which has fixed my issue!

Groundhog 08-19-2016 09:27 PM

It is - I actually have no idea what _random is, I know there's a few libraries with the underscores.

Another quick tip - you don't need the (0,8) with range, you can just:
Code:

for i in range(8):
  A.append(4 + random.random())


SirBlurton 08-22-2016 11:50 AM

You could also use a list comprehension to skip the step of appending to the created list and just create the list.

Code:

A=[(4+random.random()) for i in range(8)]

List comprehensions were one of the best things I've learned about. I had one block of about 12 overly complicated lines in an early project get replaced by one list comprehension....and that simplification flowed through everything else.

Groundhog 12-12-2016 10:16 PM

Yes, list comprehensions are the bomb once you get a handle on them. I remember reading through one of my first Python books and my eyes just glazed over when covering that topic (similar to what used to happen to me back in school in maths, actually... I wonder if I have dyscalculia...). It was only when I saw a real simple example in someone else's code that was clearly commented that it clicked with me.

Groundhog 12-12-2016 11:43 PM

It’s been months, so here’s a quick update:

Life and holidays got in the way for the most part since my last updates, but over the past three weeks I’ve picked this up again and got quite a bit done. One of the big changes I’ve made is just to focus entirely on the code component, and so I’ve sliced the GUI (PySide) right out at the moment. The main advantage to putting the UI aside is that it was really slowing me down, and my plan is to try and get the core functionality coded before looking at a UI again. If I’m happy with what I’ve coded I may just pay someone else to do it.

I think PySide is great, but I don’t know that I would ever be able to package it in a way that I’d like, and I also think that if I ever wanted to make money from this at some point, it makes sense to focus on the online/browser based component. This is contrary to how I myself like to play, but hey, I have massive CD and DVD collections too. I'm no design expert or anything, but I liked the overall style I came up with with my PySide GUI, and I'd probably want something very similar no matter which way I go. The code as I've been writing it will make it pretty easy to slot any UI framework over the top, so I can worry about this decision later, once I have a functioning simulator!

Groundhog 12-13-2016 04:12 AM

Testing out the 'universe generator' code I setup ages ago to make sure it all still works after cutting my code to pieces. Right now it uses the fictional default league info I've saved into a csv and generates fictional teams for all leagues based on that info, selecting random cities (weighted towards the most populous cities) and nicknames (if enabled). There is a ton of loading of csv files and calculations to make this info, which is what impresses me about Python - it's done in less than a second (excluding players - they take about 1.5 seconds at the moment).

I want to quickly be able to spin up entire random universes with teams/coaches/players/arenas etc. quickly to help with testing down the road.

For fun, here's the most recent USA 'NBA':

Quote:

San Jose Seagulls (SAJ): City: San Jose, CA, Popularity: 3, Arena: 1078, FG_Colour: #AF906A BG_Colour: #990000
Nashville Tigers (NAS): City: Nashville, TN, Popularity: 4, Arena: 1079, FG_Colour: #FFC700 BG_Colour: #00386B
Albuquerque Bruins (ALB): City: Albuquerque, NM, Popularity: 1, Arena: 1080, FG_Colour: #243760 BG_Colour: #F07422
Minneapolis Jaguars (MIN): City: Minneapolis, MN, Popularity: 2, Arena: 1081, FG_Colour: #00457C BG_Colour: #FF2222
Mesa Vikings (MES): City: Mesa, AZ, Popularity: 3, Arena: 1082, FG_Colour: #FFFFFF BG_Colour: #005D28
San Antonio Leopards (SAN): City: San Antonio, TX, Popularity: 5, Arena: 1083, FG_Colour: #003399 BG_Colour: #FF9900
San Diego Bucks (SAD): City: San Diego, CA, Popularity: 2, Arena: 1084, FG_Colour: #F8B800 BG_Colour: #000000
Philadelphia Thunderbirds (PHI): City: Philadelphia, PA, Popularity: 4, Arena: 1085, FG_Colour: #B31F29 BG_Colour: #11351A
Washington Stallions (WAS): City: Washington, DC, Popularity: 2, Arena: 1086, FG_Colour: #C41E3A BG_Colour: #321414
Virginia Beach Hornets (VIR): City: Virginia Beach, VA, Popularity: 3, Arena: 1087, FG_Colour: #BDB76B BG_Colour: #000000
Colorado Springs Ospreys (COS): City: Colorado Springs, CO, Popularity: 3, Arena: 1088, FG_Colour: #000000 BG_Colour: #FFC94B
Santa Ana Hawks (SAN): City: Santa Ana, CA, Popularity: 2, Arena: 1089, FG_Colour: #FFFFFF BG_Colour: #D2DDFC
Honolulu Salukis (HON): City: Honolulu, HI, Popularity: 3, Arena: 1090, FG_Colour: #FFFFFF BG_Colour: #990000
Arlington Eagles (ARL): City: Arlington, TX, Popularity: 3, Arena: 1091, FG_Colour: #000000 BG_Colour: #DC143C
Austin Barons (AUS): City: Austin, TX, Popularity: 3, Arena: 1092, FG_Colour: #374EA1 BG_Colour: #FFF200
Raleigh Miners (RAL): City: Raleigh, NC, Popularity: 4, Arena: 1093, FG_Colour: #000066 BG_Colour: #FFFFFF
Chicago Pirates (CHI): City: Chicago, IL, Popularity: 2, Arena: 1094, FG_Colour: #000000 BG_Colour: #CC0000
Denver Bees (DEN): City: Denver, CO, Popularity: 4, Arena: 1095, FG_Colour: #50C878 BG_Colour: #0047AB
Phoenix Nighthawks (PHX): City: Phoenix, AZ, Popularity: 3, Arena: 1096, FG_Colour: #FFFFFF BG_Colour: #0000FF
Tucson Flames (TUC): City: Tucson, AZ, Popularity: 2, Arena: 1097, FG_Colour: #000000 BG_Colour: #E00122
Saint Paul Centaurs (SAP): City: Saint Paul, MN, Popularity: 3, Arena: 1098, FG_Colour: #EF6E22 BG_Colour: #216EB7
Dallas Comets (DAL): City: Dallas, TX, Popularity: 1, Arena: 1099, FG_Colour: #FFFFFF BG_Colour: #000070
Riverside Kings (RIV): City: Riverside, CA, Popularity: 5, Arena: 1100, FG_Colour: #FFFFFF BG_Colour: #5858FA
Los Angeles Hawks (LAS): City: Los Angeles, CA, Popularity: 3, Arena: 1101, FG_Colour: #FFFDD0 BG_Colour: #960018
St. Petersburg Riverhawks (STP): City: St. Petersburg, FL, Popularity: 5, Arena: 1102, FG_Colour: #C5B358 BG_Colour: #8B0000
Houston Defenders (HOU): City: Houston, TX, Popularity: 1, Arena: 1103, FG_Colour: #613005 BG_Colour: #FF7300
Louisville Yellow Jackets (LOI): City: Louisville, KY, Popularity: 4, Arena: 1104, FG_Colour: #FF9900 BG_Colour: #000000
Milwaukee Wolves (MIL): City: Milwaukee, WI, Popularity: 3, Arena: 1105, FG_Colour: #CAB388 BG_Colour: #00285C
New York Cavaliers (NYK): City: New York, NY, Popularity: 4, Arena: 1106, FG_Colour: #990000 BG_Colour: #000066
Jersey City Falcons (JER): City: Jersey City, NJ, Popularity: 3, Arena: 1107, FG_Colour: #FFD700 BG_Colour: #000000

Usually it's very Texas heavy as I used a list of the 80ish most populated cities in the USA.

And the same for Spain:

Quote:

Alicante (ALI): City: Alicante, Popularity: 1, Arena: 941, FG_Colour: #FF652B BG_Colour: #4C230E
Pamplona (PAM): City: Pamplona, Popularity: 4, Arena: 942, FG_Colour: #FFFFFF BG_Colour: #006000
Valencia (VAL): City: Valencia, Popularity: 1, Arena: 943, FG_Colour: #C41E3A BG_Colour: #321414
Vitoria-Gasteiz (VIT): City: Vitoria-Gasteiz, Popularity: 2, Arena: 944, FG_Colour: #FFFFFF BG_Colour: #00386D
Madrid (MAD): City: Madrid, Popularity: 4, Arena: 945, FG_Colour: #ED1C24 BG_Colour: #F5EE30
Valladolid (VAL): City: Valladolid, Popularity: 3, Arena: 946, FG_Colour: #CFB53B BG_Colour: #006633
A Coruña (ACO): City: A Coruña, Popularity: 4, Arena: 947, FG_Colour: #FFFFFF BG_Colour: #461D7C
Getafe (GET): City: Getafe, Popularity: 4, Arena: 948, FG_Colour: #FFAC2C BG_Colour: #240A67
Bilbao (BIL): City: Bilbao, Popularity: 3, Arena: 949, FG_Colour: #662D91 BG_Colour: #F7BE19
Oviedo (OVI): City: Oviedo, Popularity: 2, Arena: 950, FG_Colour: #EFEFEF BG_Colour: #002F30
Córdoba (COR): City: Córdoba, Popularity: 5, Arena: 951, FG_Colour: #FFFFFF BG_Colour: #00A000
Sabadell (SAB): City: Sabadell, Popularity: 2, Arena: 952, FG_Colour: #FFC61E BG_Colour: #000C03
Málaga (MAL): City: Málaga, Popularity: 3, Arena: 953, FG_Colour: #FAE051 BG_Colour: #002469
Castellón de la Plana (CAS): City: Castellón de la Plana, Popularity: 3, Arena: 954, FG_Colour: #0021A5 BG_Colour: #FF4A00
Santander (SAN): City: Santander, Popularity: 3, Arena: 955, FG_Colour: #000000 BG_Colour: #F47B20
Badajoz (BAZ): City: Badajoz, Popularity: 3, Arena: 956, FG_Colour: #818285 BG_Colour: #105D95
Lleida (LLE): City: Lleida, Popularity: 2, Arena: 957, FG_Colour: #FF652B BG_Colour: #002E4D
Vigo (VIG): City: Vigo, Popularity: 5, Arena: 958, FG_Colour: #FFCC33 BG_Colour: #000000


SirBlurton 12-14-2016 04:25 PM

Very cool! It's interesting to watch your decision making process as you work through the project! Probably a wise move to put GUI aside, from screenshots it looks like you've done enough to know you can do that if that's the direction you want to go!

If there are ever any tasks you think you could use a hand with let me know...I'm still very much a beginner but I've been working away at building little bits and pieces like name generators and cartoon face generators. Just starting to learn about databases and flask right now.

I know that would likely be too complicated to manage and it's also "your baby" - but just wanted to put it out there if there's ever a piece you could use help on.

Continuing to watch for your updates! :)

Groundhog 12-14-2016 09:26 PM

Yeah, and as a plus I've learnt a good deal about PySide/PyQt/Qt, and have developed UIs for a bunch of other small projects at home and in the office, and created my first "proper" python module to manage stylesheets for widgets, the creatively named qt_widgetstyler, so it has not been time wasted!

While I do think of this as "my baby" to some extent, I'm more than open to help. By no means feel obligated to tackle this, but one thing I was playing with months and months ago and couldn't get it to work quite right is a round-robin schedule creator. When I get a chance I'll post what I put together, and if you can get the dang thing to work, fantastic! It's harder than it sounds, because it needs to take into account a few factors, such as valid days of the week to schedule games, etc. :)

SirBlurton 12-15-2016 01:53 PM

I have played with scheduling a bit and I definitely wouldn't go in thinking it's easy! But that would be cool to take a look at it...like you said, if I can't do it, it'll be something you can look at again in the future but I'd be interested in taking a crack at it!

CraigSca 12-15-2016 03:05 PM

I don't want to steal sirBlurton's thunder, but I wouldn't mind lending a hand with things, either. I've been programming my own college football sim but it's coming in drips and drabs and wouldn't mind increasing my skill set.

Groundhog 12-15-2016 09:15 PM

Hey, the more the merrier as far as I'm concerned :D

Here's a snippet of what I put together actually nearly 12 months ago, checking the time stamp of the file. I've made a few small changes just now, but I haven't tested anything yet, so there may be typos/errors if you try run the below currently (just working out of notepad at the moment...) :)

The part that was frustrating me was the 'get_valid_game_days' method. There's nothing in the code below for this, but I spent an hour or so playing around on the python command line trying to solve this - basically, need to take a date range, and calculate all the valid game days within this range, grouped by week. The timedate library has some cool functionality that should make this possible, but I'll be darned if I could crack it - this was that "math-level" stuff I mentioned above that I struggle with.

For example, if Friday and Saturday were the only valid days, and the date range was for 4 weeks starting this week, the output of this method should be:

[[16/12/2016, 17/12/2016], [23/12/2016, 24/12/2016], [30/12/2016, 31/12/2016], [6/1/2017, 7/1/2017]]

As a rule I generally work with all dates as ordinal numbers - datetime objects have a .toordinal() method. I just trust it more, especially when writing to databases.

Code:

class ScheduleGen:


    def __init__(self, current_year=2016, season_start_month=9, season_start_day=30, season_end_month=3, season_end_day=28):
        self.current_year = current_year
        self.season_start_month = season_start_month
 

    def create_round_robin_schedule(self, team_ids=None, play_each_team=3, valid_days={'monday': False, 'tuesday': False,                                                                                        'wednesday': False, 'thursday': False,
                                                                                        'friday': True, 'saturday': True,
                                                                                        'sunday': True}):

        matchups = self.generate_round_robin_matchups(teams=team_ids, play_each_team=play_each_team)
        valid_game_days = self.get_valid_game_days(valid_game_days=valid_days)
   

    def get_valid_game_days(self, valid_game_days):
        '''
        Parameters:

        :valid_game_days: (dict) A dictionary of each day of the week and a True/False value.

        Returns:

        A list of all possible game days, in ordinal format.
        '''
        # This is where I had trouble. What is needed here is to use the current_year/season_start_month/season_start_day,
        # the current_year+1/season_end_month/season_end_date, and the valid_game_days dictionary to compile a list of
        # all available dates, grouped in weeks (to ensure teams don't always play multiple games in the same week),
        # with the dates stored as ordinals (whole numbers - a feature of the timedate module), similar to this:
        # valid_dates = [[734228, 734229],[734235, 734236],[734241. 734242]] etc.
        pass

    @staticmethod
    def generate_round_robin_matchups(teams=None, play_each_team=1):
        '''
        Note: Bulk of this code taken from: https://gist.github.com/Makistos/7192777

        Parameters:

        :teams: (list) league team IDs.
        :play_each_team: (int) how many times all teams play each other.

        Returns:

        A list of all valid matchups.
        '''
        matchups = []

        if len(teams) % 2 == 1:
            #teams = teams + ['BYE']
            teams.append(False)

        for i in range((len(teams) - 1) * play_each_team):

            mid = round(len(teams) / 2)
            l1 = teams[:mid]
            l2 = teams[mid:]
            l2.reverse()       
           
            # Switch sides after each round
            if(i % 2 == 1):
                matchups = matchups + [ zip(l1, l2) ]
            else:
                matchups = matchups + [ zip(l2, l1) ]

            teams.insert(1, teams.pop())

        return matchups


Groundhog 12-15-2016 09:21 PM

dola

The above was written in Python 2 as well, where as I've moved to 3 now. I think the only impact this has on the above is that the 'generate_round_robin_matchups' method will returns a generator object rather than a list of lists, but this is minor.

edit: fixed some typos in the above.

CraigSca 12-18-2016 10:39 AM

Is the valid_game_day list only for a single week or for all weeks? Meaning, do I want to state that Mondays and Tuesdays are invalid game dates for ALL weeks, or do I just want an potentially long list showing which days are invalid for the entire year?

Groundhog 12-18-2016 05:14 PM

For all weeks - so a long list of dates, grouped by weeks, between a start date and end date. What I'm trying to achieve here is a list of all valid game days between two dates. The next step would be assigning all the matchups generated by the 'generate_round_robin_matchups' method to these dates.

Most of the "round robin" leagues around the world have set days that they usually play their games - for European leagues it's generally Sat/Sun (which makes the Euroleague/Eurocup scheduling easier), in Australia it's everyday except Tue/Weds - so that's the behaviour I'm looking for here. The leagues all have the 'valid days' attribute that defines which of these days of the week to schedule games on. This class (will eventually) take that info as a dictionary, generate a list of all the matchups, generate a list of valid game dates, and then assign those matchups to those dates.

CraigSca 12-19-2016 09:16 AM

Quote:

Originally Posted by Groundhog (Post 3136147)
For all weeks - so a long list of dates, grouped by weeks, between a start date and end date. What I'm trying to achieve here is a list of all valid game days between two dates. The next step would be assigning all the matchups generated by the 'generate_round_robin_matchups' method to these dates.

Most of the "round robin" leagues around the world have set days that they usually play their games - for European leagues it's generally Sat/Sun (which makes the Euroleague/Eurocup scheduling easier), in Australia it's everyday except Tue/Weds - so that's the behaviour I'm looking for here. The leagues all have the 'valid days' attribute that defines which of these days of the week to schedule games on. This class (will eventually) take that info as a dictionary, generate a list of all the matchups, generate a list of valid game dates, and then assign those matchups to those dates.


Stupid question - and now I see why working in teams can sometimes be hard - when you generate the list of invalid game days (the "falses" in the list) can't you just generate the "trues" as a list for the entire year, keep it in memory and just access it when needed?

Groundhog 12-19-2016 06:23 PM

No, not a stupid question at all!

Ignore the invalid dates, because we only need those to determine which days are valid, and they will be skipped over. The False/True flags just tell the method that it needs to compile a list of all True days for each week between a range of dates. So if we feed the class a starting date of June 30 2016 up until January 31 2017, the method would first check which days are valid - let's say Saturday and Sunday - and then split up the the period between those dates into units of weeks, and append all the dates of Saturday and Sundays to a list. When we assign the matchups to days, it would be a random.choice() type of operation to randomly assign the individual matchups to these valid dates.

This could all be stored in memory, but this calculation will need to be run for all 70ish leagues once per offseason, as they all have their own unique True/False flags for valid game days, and obviously the dates will also change from year to year.

The final output of this would be a list of all games in a season, with the date, league id, home team id, and road team id, which would then be written to the database.

An instance of this class would be used inside another method somewhere along the lines of (and this is probably full of syntax errors, but just to give you a quick idea):

Code:

def generate_all_schedules(dict_of_all_leagues, dict_of_all_teams, current_year=2016, season_start_month=9, season_start_day=30, season_end_month=3,
                          season_end_day=28):
    # dict_of_all leagues: A dictionary with league_id as the key, all league attributes as values in another dict.
    # dict_of_all_teams: A dictionary with the league_id as the key, and all team ids in a list as value.

    season_schedule = []

    sg = ScheduleGen(current_year, season_start_month, season_start_day, season_end_month, season_end_day)

    for league in dict_of_all_leagues:
        # Create a 'shortcut' reference directly to the league to be processed
        l = dict_of_all_leagues[league]
        # Create a 'shortcut' reference to list of teams in league
        t = dict_of_all_teams[l['id']]

        league_sched = sg.create_round_robin_schedule(team_ids=dict_of_all_teams[l['id']], play_each_team=l['play_each_team'], valid_game_days=l['valid_game_days'])
       
        season_schedule.append(league_sched)

    return season_schedule


Groundhog 12-19-2016 08:08 PM

dola

Had another thought. Maybe the way to approach it is to just create a dictionary once of every week and day of the week in that date range, and then use that info to build all the schedules.

CraigSca 12-20-2016 10:11 AM

Quote:

Originally Posted by Groundhog (Post 3136339)
No, not a stupid question at all!

Ignore the invalid dates, because we only need those to determine which days are valid, and they will be skipped over. The False/True flags just tell the method that it needs to compile a list of all True days for each week between a range of dates. So if we feed the class a starting date of June 30 2016 up until January 31 2017, the method would first check which days are valid - let's say Saturday and Sunday - and then split up the the period between those dates into units of weeks, and append all the dates of Saturday and Sundays to a list. When we assign the matchups to days, it would be a random.choice() type of operation to randomly assign the individual matchups to these valid dates.

This could all be stored in memory, but this calculation will need to be run for all 70ish leagues once per offseason, as they all have their own unique True/False flags for valid game days, and obviously the dates will also change from year to year.

The final output of this would be a list of all games in a season, with the date, league id, home team id, and road team id, which would then be written to the database.

An instance of this class would be used inside another method somewhere along the lines of (and this is probably full of syntax errors, but just to give you a quick idea):

Code:

def generate_all_schedules(dict_of_all_leagues, dict_of_all_teams, current_year=2016, season_start_month=9, season_start_day=30, season_end_month=3,
                          season_end_day=28):
    # dict_of_all leagues: A dictionary with league_id as the key, all league attributes as values in another dict.
    # dict_of_all_teams: A dictionary with the league_id as the key, and all team ids in a list as value.

    season_schedule = []

    sg = ScheduleGen(current_year, season_start_month, season_start_day, season_end_month, season_end_day)

    for league in dict_of_all_leagues:
        # Create a 'shortcut' reference directly to the league to be processed
        l = dict_of_all_leagues[league]
        # Create a 'shortcut' reference to list of teams in league
        t = dict_of_all_teams[l['id']]

        league_sched = sg.create_round_robin_schedule(team_ids=dict_of_all_teams[l['id']], play_each_team=l['play_each_team'], valid_game_days=l['valid_game_days'])
       
        season_schedule.append(league_sched)

    return season_schedule



Yeah - getting back to my question - does that mean the list of true/false flags are ONLY for days of the week, or could you have something like false for all Saturdays and also Christmas day?

Groundhog 12-20-2016 05:27 PM

Quote:

Originally Posted by CraigSca (Post 3136446)
Yeah - getting back to my question - does that mean the list of true/false flags are ONLY for days of the week, or could you have something like false for all Saturdays and also Christmas day?


Currently, only for days of the week. I did think about things like holidays, but at the same time its a lot of work tracking down holidays/special days for 68 different nations, to have things like no Christmas day games in Australia, or no Sunday games in Israel, etc.

Young Drachma 01-31-2017 04:49 AM

Spam aside, glad you're still at this.

GoldenCrest Games 03-05-2017 05:27 PM

Nice to see you're still chugging along!

nilodor 07-07-2017 10:24 AM

Quote:

Originally Posted by Groundhog (Post 3080333)
Until this point I've imported all of my data - teams, coaches, leagues, nations, etc. - in a database (sqlite) that I manually populated from csvs full of info I've gathered over the last couple of years, so I spent some time the past couple of days putting together the 'new game' process - main menu/league selections, etc.

Here's a couple of screens:

Title Screen
A quick (5 minute) title screen just to give the standard new/continue/load options.


New Game Menu
This one took a lot longer - the fully functional league selection screen. All the data here is taken from csv files that can be easily modified to add/subtract/modify the leagues included - currently 44 fields per league (some repetitive, like 7 fields for each day of the week that games will be scheduled). Leagues where I've manually created teams (also done via csvs) default to 'import' teams, other leagues will be randomly generated. Active leagues will be bolded (not yet done), and I'll ditch the '#' in the Teams column header.

The Olympics/Tournaments options on the left will be changed to a table like the regional leagues, because it gives me more flexibility with how many I can include without running out of room - there's international tournaments in the Americas, Asia and Africa that I don't plan on looking at now but would probably like to look at down the track:



Nav Bar
Lastly, the top-of-screen navigation bar - not completely functional yet, because I don't have all the screens completed. This image is at 100% actual width, to give you an idea of how wide the UI will be:


What did you use to make these screens? They look great, much better than what I'm capable of in PyQt

Groundhog 07-09-2017 06:44 AM

Quote:

Originally Posted by nilodor (Post 3166003)
What did you use to make these screens? They look great, much better than what I'm capable of in PyQt


Just a combination of the Designer app to layout all the widgets, and then applying different stylesheets to each widget within Python. Most of the "magic" is just labels with rounded corners and partially transparent background colours (rgba with an alpha channel that acts as the transparency %), so the background image shows through.

nilodor 07-19-2017 03:15 PM

Quote:

Originally Posted by Groundhog (Post 3166123)
Just a combination of the Designer app to layout all the widgets, and then applying different stylesheets to each widget within Python. Most of the "magic" is just labels with rounded corners and partially transparent background colours (rgba with an alpha channel that acts as the transparency %), so the background image shows through.


To get the rounded push buttons did you use something like:

Code:

self.pushButton.setPalette(palette)
self.pushButton.setStyleSheet("background-color: rgb(170, 255, 255); border-style:solid; border-color:black; border-radius:20px;border-width:2px;")
self.pushButton.setObjectName("pushButton")


I can't seem to get rounded edges this way

Groundhog 07-19-2017 10:10 PM

Code:

standard_button = '''QPushButton {{
                                  color: rgb{};
                                  background-color: rgb{};
                                  border-bottom-left-radius: {}px;
                                  border-bottom-right-radius: {}px;
                                  border-top-left-radius: {}px;
                                  border-top-right-radius: {}px;
                                }}
                    QPushButton:hover {{
                                        background-color: rgb{};
                                      }}
                    QPushButton:checked {{
                                          background-color: rgb{};
                                          color: rgb{};
                                        }}
                    QPushButton:disabled {{
                                            color: rgb{};
                                            background-color: rgb{};
                                            border: none;
                                          }}'''


I can't remember if there's a good reason why I used individual corner radius %s vs just a general border-radius setting. Swap out the {} for values and that's straight out of my code.

I didn't use the setPalette or .setObjectName methods for any of my widgets - again, can't remember if that was for a reason or if I just never saw those methods. I created this library to let me group widgets and make it easier to manage colour schemes on different team pages, etc. It's super amateur and I'm sure Qt has a way of doing the same thing (possibly .setObjetcName), but it was an easier "python" way for me to handle it.

nilodor 07-20-2017 09:15 AM

Quote:

Originally Posted by Groundhog (Post 3167032)
Code:

standard_button = '''QPushButton {{
                                  color: rgb{};
                                  background-color: rgb{};
                                  border-bottom-left-radius: {}px;
                                  border-bottom-right-radius: {}px;
                                  border-top-left-radius: {}px;
                                  border-top-right-radius: {}px;
                                }}
                    QPushButton:hover {{
                                        background-color: rgb{};
                                      }}
                    QPushButton:checked {{
                                          background-color: rgb{};
                                          color: rgb{};
                                        }}
                    QPushButton:disabled {{
                                            color: rgb{};
                                            background-color: rgb{};
                                            border: none;
                                          }}'''


I can't remember if there's a good reason why I used individual corner radius %s vs just a general border-radius setting. Swap out the {} for values and that's straight out of my code.

I didn't use the setPalette or .setObjectName methods for any of my widgets - again, can't remember if that was for a reason or if I just never saw those methods. I created this library to let me group widgets and make it easier to manage colour schemes on different team pages, etc. It's super amateur and I'm sure Qt has a way of doing the same thing (possibly .setObjetcName), but it was an easier "python" way for me to handle it.


Weird, doing each corner separately seems to work. I think that you have to use the palette command if you're using PyQt5. Like how the QMainWindow moved from PyGui to QtWidgets.

One thing I'm going to have to work on is the ability to batch import. I've got it set up that I can read in constants from a text file for athlete generation, but I'm not sure how to do it to create a generic style sheet based on the country the player is using.

Maybe I'll actually post in my thread to discuss it better. :)

Groundhog 07-20-2017 10:02 PM

Happy to show you how I do it, PM me if you want a quick example.

CrescentMoonie 07-20-2017 10:21 PM

Enjoyed reading through this. I'm at the very beginning of my journey learning languages, starting with a couple of web developer courses through Udemy (nearly everything on the site was $10 around July 4). After that I'm looking at Ruby on Rails, I already bought an intro course on it, and maybe Python after that. This dynasty will definitely help in my sections on Python in the two developer courses.

Groundhog 06-25-2019 06:43 PM

Just an update on this, because I get the odd PM here and there, especially from folks who find this thread via google. The two questions I get are:

Did I ever finish this? No. Real life, in particular a promotion at work and having a kid, made this begin to feel like work to be completely honest. I was spending 2-3 hours a night coding in bed, and I was beginning to have dreams involving Python functions, which was a bit strange. I decided to take a break from it and never got the urge to pick it up again. I'm sure I will down the line however, and I've still kept up with Python and use it from time-to-time at work.

Is it possible to program something like this in Python? Absolutely yes, and probably a lot better than how I was doing it. Even the GUI I think looked OK, but as I touched on a few times in this thread I would ignore this component it if I did this again and look at a web GUI (and probably paying someone to build one rather than learning it myself).


All times are GMT -5. The time now is 04:44 AM.

Powered by vBulletin Version 3.6.0
Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.