Results 1 to 12 of 12
  1. #1
    Digital Larry is offline Member
    Join Date
    Mar 2013
    Posts
    87
    Rep Power
    0

    Default Question about design strategy for UIs

    OK this question is not Swing specific, but since I'm using Swing I figured people might have some insight into good design practices.

    I have written a CAD system in Swing/Java. This involves placing, moving, deleting and connecting blocks.

    I generally process MousePressed and MouseMoved events. I also have several different states that the UI can be in.

    For example, if I left-click in the middle of a block, I switch to "BLOCKMOVE" mode and then I'm moving it around until I left-click again to drop it. If I right-clicked while in BLOCKMOVE mode then I'd cancel the operation.

    The logic I'm writing to handle all this is starting to look ridiculous and I'm curious if there's a standard strategy for designing these types of UIs.

    As I said before, I track MousePressed events.
    When this happens, I want to know:
    1) Which mouse button was it? (L or R)
    2) What mode am I in? (DRAGMODE or GROUPDRAGMODE or GROUPSELECTMODE or CONNECT or NONE)
    3) Did I hit a block? or did I hit a pin? or did I hit nothing? (3 choices)

    As you can see, for each question, I have to ask the subsequent questions for each possible answer to the first question, and so forth.

    Mouse Button = 2 choices
    What Mode = 5 choices
    What did I hit? = 3 choices

    So for this simplified system, there are already 30 possible code paths (probably reduced because some combinations are not used). And the number of possibilities doesn't depend on which order I ask the questions in.

    I could see putting all this into a table, which certainly helps with the design and understanding, but I'm unaware of any code structures that would allow me to leverage that to any extent.

    Is there a "recommended" way to handle this?

    Thanks,

    DL

  2. #2
    jim829 is offline Senior Member
    Join Date
    Jan 2013
    Location
    Northern Virginia, United States
    Posts
    6,226
    Rep Power
    13

    Default Re: Question about design strategy for UIs

    Without more information I assume you are using your own objects which draw themselves and detect when they are the ones being selected. These blocks would be nothing more than a width, height, and current location.

    Regards,
    Jim
    The JavaTM Tutorials | SSCCE | Java Naming Conventions
    Poor planning on your part does not constitute an emergency on my part

  3. #3
    Digital Larry is offline Member
    Join Date
    Mar 2013
    Posts
    87
    Rep Power
    0

    Default Re: Question about design strategy for UIs

    Quote Originally Posted by jim829 View Post
    Without more information I assume you are using your own objects which draw themselves and detect when they are the ones being selected. These blocks would be nothing more than a width, height, and current location.

    Regards,
    Jim
    Hey Jim,

    You are 100% correct about that. The on screen doodads are not extensions of JComponent and I totally keep track of them and draw them with my own code.

    DL

  4. #4
    jim829 is offline Senior Member
    Join Date
    Jan 2013
    Location
    Northern Virginia, United States
    Posts
    6,226
    Rep Power
    13

    Default Re: Question about design strategy for UIs

    Well, to further the discussion, I would also expect that each one receives the same events and can do self determination if it is the one to move. But even if I am correct, I can't really offer any guidance without seeing some sort of code and understanding how your states are increasing geometrically. It may be that what you are doing is the way to do it and just goes with the territory.

    Regards,
    Jim
    The JavaTM Tutorials | SSCCE | Java Naming Conventions
    Poor planning on your part does not constitute an emergency on my part

  5. #5
    Digital Larry is offline Member
    Join Date
    Mar 2013
    Posts
    87
    Rep Power
    0

    Default Re: Question about design strategy for UIs

    Here's the code in question.

    Now that I look at it, I think the issue is more that I could read variables or do function calls to get all of the information up front prior to determining what the next state should be (it's just a state machine after all). But the way I'm doing it is to ask the questions one at a time, which means that I have code to determine whether or not I hit a pin in several places, which seems stupid. I think it would be cool to organize this simply as a table-based state machine, but I currently wind up with nested redundant if statements. Btw I'm self taught in Java and so it's quite possible I am missing something that "everyone" should know.

    Java Code:
    		addMouseListener(new MouseAdapter() {
    			@Override
    			public void mousePressed(MouseEvent arg0) {
    				// drop a line or block if you were dragging it
    				if(dm == dragModes.DRAGMOVE) {
    					spdFrame.getModel().setChanged(true);
    					dm = dragModes.NODRAG;
    					dragLine = null;
    					return;
    				}
    				if(arg0.getButton() == 3) {		// right mouse button
    					if(dm == dragModes.CONNECT) {
    						dm = dragModes.NODRAG;
    						dragLine = null;
    					}
    					else {
    						// right clicked on pin, look to see if hit on/near pin and if so, delete connection.
    						Point point = getNearbyPoint();
    						if(point != null) {
    							SpinCADBlock b = null;	
    							Iterator<SpinCADBlock> itr = spdFrame.getModel().blockList.iterator();
    							while(itr.hasNext()) {
    								b = itr.next();
    								Iterator<SpinCADPin> itrPin = b.pinList.iterator();
    								SpinCADPin currentPin = null;
    								while(itrPin.hasNext()) {
    									currentPin = itrPin.next();
    									// hit a block pin, so connect it
    									// bug here somewhere
    									if(hitPin(arg0, b, currentPin)) {
    										currentPin.deletePinConnection();
    										f.getModel().setChanged(true);
    										f.updateFrameTitle();
    										return;
    									}
    								}
    							}
    						}
    					}
    				}
    				SpinCADBlock b = null;	
    				Iterator<SpinCADBlock> itr = spdFrame.getModel().blockList.iterator();
    				while(itr.hasNext()) {
    					b = itr.next();
    					// if we hit the block, we can either delete or drag it
    					if (hitTarget(arg0, b) == true) {
    						// System.out.println("Direct hit!");
    						switch(dm) {
    						case NODRAG:
    							if(arg0.getButton() == 1) {	// left button
    								spdFrame.getModel();
    								SpinCADModel.setCurrentBlock(b);
    								dm = dragModes.DRAGMOVE;
    							}
    							else if (arg0.getButton() == 3)	{	// right button
    								doPop(arg0, b);
    							}
    						default:
    							break;
    						}
    						repaint();
    						return;
    					}
    					else {
    						Iterator<SpinCADPin> itrPin = b.pinList.iterator();
    						SpinCADPin currentPin = null;
    						while(itrPin.hasNext()) {
    							currentPin = itrPin.next();
    							// hit a block pin, so connect it
    							// bug here somewhere
    							if(hitPin(arg0, b, currentPin)) {
    								if(dm != dragModes.CONNECT) {
    									System.out.println("Connect start!");
    									dm = dragModes.CONNECT;	// now we're going to connect a wire
    									startBlock = b;
    									startPin = currentPin;
    								}
    								else {		// we already were dragging a wire, now place it
    									if(startPin.isOutputPin() && currentPin.isInputPin()) {
    										stopBlock = b;
    										if(startBlock != stopBlock) {
    											// decrement count of pin which was connected
    											SpinCADPin p = currentPin.getPinConnection();
    											if(p != null) {
    												currentPin.deletePinConnection();
    											}
    											stopPin = currentPin;
    											stopPin.setConnection(startBlock,  startPin);		
    											// XXX debug set pin connections in both directions don't think this works
    											// startPin.setConnection(stopBlock,  stopPin);
    											System.out.println("Connect stop!");
    											dm = dragModes.NODRAG;
    											dragLine = null;
    											startBlock = null;
    											spdFrame.getModel().setChanged(true);
    											spdFrame.getResourceToolbar().update();	// recalculate model resources toolbar
    											f.updateFrameTitle();
    											repaint();
    										}
    									}
    									else if (startPin.isInputPin() && currentPin.isOutputPin()) {
    										stopBlock = b;
    										if(startBlock != stopBlock) {
    											stopPin = currentPin;
    											// XXX debug set pin connections in both directions don't think this works
    											startPin.setConnection(stopBlock,  stopPin);	
    											// stopPin.setConnection(startBlock,  startPin);		
    											System.out.println("Connect stop!");
    											dm = dragModes.NODRAG;
    											dragLine = null;
    											startBlock = null;
    											spdFrame.getModel().setChanged(true);
    											f.updateFrameTitle();
    											spdFrame.getResourceToolbar().update();	// recalculate model resources toolbar
    											repaint();
    										}
    									}
    								}
    								return;
    							}
    						}
    					}
    				}
    			}
    		});

  6. #6
    Digital Larry is offline Member
    Join Date
    Mar 2013
    Posts
    87
    Rep Power
    0

    Default Re: Question about design strategy for UIs

    Just to be clear, the code functions 100% correctly as-is. I am planning to add more functionality and it struck me that I might benefit from a different structure to more closely match the concept of a finite state machine. I did look at some FSM Java examples and got some ideas. In this case, the variable dm ("Drag mode") refers to an enum of possible states.

  7. #7
    jim829 is offline Senior Member
    Join Date
    Jan 2013
    Location
    Northern Virginia, United States
    Posts
    6,226
    Rep Power
    13

    Default Re: Question about design strategy for UIs

    This seems to be a lot of code for an event handler. And there are certain places you do things that you don't seem to use (like line 51 above where you get a model but don't seem to use it or assign it). Do you have this action listener in each of your blocks that you are moving?

    Regards,
    Jim
    The JavaTM Tutorials | SSCCE | Java Naming Conventions
    Poor planning on your part does not constitute an emergency on my part

  8. #8
    Digital Larry is offline Member
    Join Date
    Mar 2013
    Posts
    87
    Rep Power
    0

    Default Re: Question about design strategy for UIs

    Quote Originally Posted by jim829 View Post
    This seems to be a lot of code for an event handler. And there are certain places you do things that you don't seem to use (like line 51 above where you get a model but don't seem to use it or assign it). Do you have this action listener in each of your blocks that you are moving?

    Regards,
    Jim
    Hi Jim,

    Thanks for humoring me. Let's see, this handler is in the JPanel that is in the JFrame of the application. And it's the only one. The "model" is a sorted list of the blocks, so what those iterators are generally doing is iterating through each block in the list. I probably stated my initial problem poorly. As I said, the existing code works fine but is structurally odd in my opinion. As far as that isolated getModel() call I don't recall why it's there. There's probably a good reason.

    Let me try to state my structural dilemma a different way.

    Suppose we are trying to implement an FSM with several inputs, states, and actions.

    Should I completely describe my different states in a single "if" statement apiece? As written, my code first checks to see if the right button is held down - if so, then it goes on to check some other things. And if not, it continues on to something else. Now ultimately these dependent conditions might well translate to the states I had in mind, but it sure is not obvious or very readable what those various states are. Adding more states becomes difficult because of the circuitous structure, whereas (I believe) that if each state were complete and isolated, with appropriate action and next state defined, then adding more states would be relatively trivial.

    Thx,

    DL

  9. #9
    jim829 is offline Senior Member
    Join Date
    Jan 2013
    Location
    Northern Virginia, United States
    Posts
    6,226
    Rep Power
    13

    Default Re: Question about design strategy for UIs

    Unfortunately I am unable to recommend a specific technique on how to modularize your existing code. But I would have each of my objects implement the appropriate listener and handle as much of their own interaction themselves rather than using a central listener. I also might think about using property listeners for receiving and/or recording state (this may also be ill conceived). Or you could use enum maps or bit strings. There are lots of ways. And as I have been removed from computer science for quite a few years, I would probably try to find some open source code that does similar stuff and see how the authors did it. You can learn quite a bit from others code (if you trust their capabilities). I have heard the Apache projects are well designed. Finally, I would try a variety of techniques on a very small model to see how they might scale. But you will always run into situations where things can get ugly. And state tables can get real complicated fast. If you get a chance, take a look at a state table generated by Bison. Others in this forum are probably more in tune with how this might be done so wait a couple of days and see what they have to recommend.

    Regards,
    Jim
    The JavaTM Tutorials | SSCCE | Java Naming Conventions
    Poor planning on your part does not constitute an emergency on my part

  10. #10
    Digital Larry is offline Member
    Join Date
    Mar 2013
    Posts
    87
    Rep Power
    0

    Default Re: Question about design strategy for UIs

    Thanks Jim. I have done a little searching and it turns out this is a pretty ripe area for discussion (though some of these articles/threads are about 10 years old).

    SwingStates : Adding state machines to Java and the Swing toolkit - Widget toolkits
    https://www.java.net/node/658963
    A Java/Swing GUI Framework
    Programming a State Machine in Java | Wicked Source

    I think in my case, the decision revolves somewhat around introducing more "order" through construction of a real state machine, or use of other classes which do so. And since I am not planning to add a whole ton of functionality, I think what I will do is to have the first level "case" statement of my panel's mouseclick handler switch on the state rather than anything else (e.g. which button was pressed). While the end result is hopefully the same, I think readability and maintainability will improve.

    In my application, since the onscreen drawing objects are not known to Swing, they will not generate events. At one point I tried to make them conform (extending from JComponent), thinking that would make everything easier, but it didn't. So, only the JPanel has any sort of mouse handlers, and the JPanel makes calls referencing the "model" to figure out whether a specific block or pin was clicked on. It works well enough at this level of complexity.

    Thanks again for the discussion - it helped me figure out what the real point was.

    Regards,

    DL

  11. #11
    jim829 is offline Senior Member
    Join Date
    Jan 2013
    Location
    Northern Virginia, United States
    Posts
    6,226
    Rep Power
    13

    Default Re: Question about design strategy for UIs

    Quote Originally Posted by Digital Larry View Post
    In my application, since the onscreen drawing objects are not known to Swing, they will not generate events.
    Well, first, I was not talking about generating events, only receiving them. Let's say that you have five instances of a square object. And that object implements MouseListener. Now when the mouse is moved, each object will receive the events. But only the object for which the cursor is within responds. Since each object knows its position, it can do self determination as to whether the event is for itself or not.

    Second, you don't have to be a JComponent to generate events. You can use the PropertyChangeSupport class and fire them yourself. You can have add and remove listeners and any object which wants to receive events from your object just needs to implement the listener interface (also created by you). Quite often, this is done by receiving some other event that you process, then you operate on the event and in response, generate your own event. Here is an example.

    Let's say you have a dial object. You receive mouse events to rotate the dial. But when the dial is rotated, you generate a RotateDialEvent and all the methods which implemented RotateDialListener and added it to your object will receive the events.

    Regards,
    Jim
    The JavaTM Tutorials | SSCCE | Java Naming Conventions
    Poor planning on your part does not constitute an emergency on my part

  12. #12
    Digital Larry is offline Member
    Join Date
    Mar 2013
    Posts
    87
    Rep Power
    0

    Default Re: Question about design strategy for UIs

    OK I see what you mean. I don't have any theoretical basis for determining if that's a better solution or not. In practical terms, all I can tell you is that this project is something I'm doing in my spare time presumably for fun, I don't have a lot of time to devote to it, and so some of the approaches I have used may fall short of "best practices".

    Now it's interesting you should mention Listeners, as I have had to add some of those where I hadn't anticipated. Mostly for control panel things where you can use a slider for coarse adjustment of a variable, and a spinner to allow typing in an exact value for that same variable.

    Cheers,

    DL

Similar Threads

  1. Design Question
    By CChange in forum Advanced Java
    Replies: 0
    Last Post: 03-26-2011, 05:40 PM
  2. Design question: where to put sql
    By Armadillo in forum JDBC
    Replies: 3
    Last Post: 07-30-2010, 05:53 PM
  3. Replies: 2
    Last Post: 03-24-2009, 05:02 PM

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •