This page lists the milestone requirements for Milestone 4 of the CC 410 Restaurant Project. Read the requirements carefully and discuss any questions with the instructors or TAs.
The CC 410 Restaurant Project project for this semester is centered around building a point of sale (POS) system for a fictional restaurant named Starfleet Subs, based in the Star Trek universe.
The fourth milestone involves creating the various GUI windows and panels required for this project. The next milestone will involve adding functionality to these GUI elements beyond the ability to load different panels into the main window area.
This milestone must follow these professional coding standards:
__init__.py
and __main__.py
are exempt.application
plugin. The project should compile without errors.starfleetsubs.gui
package do not require type hints in Python, though you may continue to use them if they are helpful. Any errors from Mypy originating in these classes will be ignored.flake8-docstrings
and pep8-naming
plugins. Code should conform to PEP 8 style with Google style docstrings.This milestone should include the following features:
starfleetsubs.Main
class that properly loads and displays the program’s GUI.starfleetsubs.gui.MainWindow
class that represents the main GUI window.
starfleetsubs.gui.OrderPanel
class to represent the main order screen panel.
starfleetsubs.gui.SidebarPanel
class to represent the sidebar panel.
starfleetsubs.gui.entrees
package for each entrée item.
EntreePanel
class to reduce the amount of duplicate code.SidePanel
in the starfleetsubs.gui.sides
package.
Side
class. However, when buttons on the OrderPanel are clicked, you’ll need to make sure an instance of the correct item is generated.starfleetsubs.gui.drinks
package for each drink item.
DrinkPanel
class to reduce the amount of duplicate code.starfleetsubs.gui
package do not require unit tests.starfleetsubs.gui
package do not require type hints in Python, though you may continue to use them if they are helpful. Any errors from Mypy originating in these classes will be ignored.starfleetsubs.gui
package do require all appropriate documentation comments, and must be free of style errors.You are welcome to add additional methods to the existing content in the starfleetsubs.data
package. If so, make sure you include appropriate type checking and unit tests.
See below for a few sketches of what your GUI might look like.
Note
You are encouraged to use the code from Example 6 as a basis for this GUI, or you may create a different design. There are no set requirements for the design other than what is listed above, and the overall focus in this milestone is on simply getting the content on the screen and the ability to move between the various panels. You are welcome to spend additional time on the design if desired, but focus on getting the the content on the screen before doing any design work.
Completing this project is estimated to require 3-8 hours.
Tip
A rough estimate for this milestone would be around 1500 lines of new code. It could vary widely based on how you choose to implement the various portions of the GUI. I was able to reuse many portions of the example project and expand on them to build this milestone. -Russ
This assignment will be graded based on the rubric below:
Main
class - 2%MainWindow
class - 4%SidebarPanel
class - 4%OrderPanel
class - 20%SidePanel
class - 5%The following deductions apply:
This is not an exhaustive list of possible deductions. The instructors will strive to provide reasonable and fair grading, but we can’t predict all possible defects. It is up to the student to ensure that the project is complete and correct before submission.
Submit this assignment by creating a release on GitHub and uploading the release URL to the assignment on Canvas. You should not submit this Codio project or mark it as complete in Codio, in case you need to come back to it and make changes later.
Below are some GUI sketches to help you visualize one possible GUI for this project. You do not have to match this design at all, but this is at least a good starting point that you can reach based on what you learned in Example 6.
Note
I chose to increase the default size of my GUI to 1024x740 pixels, as that made the buttons fit better into the window. - Russ
Here are a couple of helpful pieces of code that you may wish to use in your project.
In many cases, I found it easiest to create private or protected methods that will construct my GridBagConstraints
objects, either within the class I was working in or in a parent class in the case of entrée and drink panels. Here’s an example:
/**
* Construct a GridBagConstraints object.
*
* @param y the y coordinate of the object
* @param start set anchor to LINE_START
* @return the constructed GridBagConstraints object
*/
protected GridBagConstraints makeGbc(int y, boolean start) {
GridBagConstraints gbc = new GridBagConstraints();
gbc.gridx = 0;
gbc.gridy = y;
if (start) {
gbc.anchor = GridBagConstraints.LINE_START;
}
gbc.insets = new Insets(2, 2, 2, 2);
return gbc;
}
Then, when I want to place something in my layout using a GridBagConstraints
object build from this method, I can use this:
this.add(check, this.makeGbc(i++, true));
The biggest benefit to this approach is that I can easily adjust all of the buttons by changing this one method. This is a great example of the “Don’t Repeat Yourself” or DRY principle.
In many cases, I found it helpful to create a dictionary of settings that I’d like use with the grid()
method, and then pass that entire dictionary as keyword arguments to the method. I usually did this either in a helper method within the class itself, or in a parent class in the case of entrée and drink panels. Here’s an example:
def _grid_dict(self, row: int, sticky: str) -> Mapping[str, Any]:
"""Create a dictionary of settings.
Args:
row: the row for the item
sticky: the sticky settings
"""
settings: Dict[str, Union[str, int]] = dict()
settings["row"] = row
settings["column"] = 1
settings["padx"] = 2
settings["pady"] = 2
settings["sticky"] = sticky
return settings
Then, when I want to place something in my layout using the grid()
method with these settings, I can use this:
checkbutton.grid(**self._grid_dict(i, "W"))
Notice that I have to place two asterisks **
before the method. That tells Python to “unpack” the dictionary returned by that method so that it can be read as individual keyword parameters. A deeper explanation is found here.
The biggest benefit to this approach is that I can easily adjust all of the buttons by changing this one method. This is a great example of the “Don’t Repeat Yourself” or DRY principle.
I also had to tell Mypy to ignore the lambda expressions used in the OrderPanel
class, as it cannot properly determine the type of the lambda. You can do this by adding a # type: ignore
comment at the end of the offending line.
button = Button(master=side_frame, text=str(side),
command=lambda x=str(side): # type: ignore
self.action_performed(x))
If anyone is able to figure out exactly how to properly get Mypy to handle this, there are major Bug Bounty points available!