I have a GUI, from this GUI I choose an input file with the dimensions of a Booking system(new GUI) If the plane has 100 seats the GUI will be for example 10x10, if the plane has 200 seats it will be 10x20, all the seats are going to be buttons, and should store passenger information on them if they are booked.Also a booked seat shall not be booked again.
The question is the dimensions of the GUI will change according to the seat numbers and orientation, which means in one version there can be lots of buttons on another less, also more seats means the GUI will be longer or wider maybe 10 cm x 10 cm or 10 cm x 20 cm, or 15 cm x 25 cm...
I am thinking to do this with a for loop but I dont want to put buttons out of the GUI.I dont know how can I add a button next to the other button arbitrarily. I always used Eclipse Window Builder for building GUIs but I guess I need to write this one on my own... can someone help me?Some hints?Thanks for your time!
Try something like this:
// The size of the window.
Rectangle bounds = this.getBounds();
// How many rows of buttons.
int numOfRows = 100;
// How many buttons per row.
int numOfColumns = 50;
int buttonWidth = bounds.width / numOfRows;
int buttonHeight = bounds.height / numOfColumns;
int x = 0;
int y = 0;
for(int i = 0; i < numOfColumns; i++){
for(int j = 0; j < numOfRows; j++){
// Make a button
button.setBounds(x, y, buttonWidth, buttonHeight);
y += buttonHeight;
}
x += buttonWidth;
}
This will make all the buttons fit inside of your window.
Here's a link on rectangles, they come in pretty handy when doing things like this.
http://help.eclipse.org/helios/index.jsp?topic=%2Forg.eclipse.platform.doc.isv%2Freference%2Fapi%2Forg%2Feclipse%2Fswt%2Fgraphics%2FRectangle.html
Also, you can still use windowbuilder, infact I recommend you do. It really helps you to visualize the dimensions you want. AND you can also create stuff (buttons, lists, dropdowns... etc) manually with code and, assuming you put the variables where WindowBuilder would, it will still display them in the 'design' tab.
Hope this helps!
EDIT: I was kinda vague on how to make buttons using a loop
To make buttons with a loop you will need a buffer (to store a temporary button long enough to add to a list) and... a list :D.
This is how it should look:
Outside loop:
// The list to store your buttons in.
ArrayList<Button> buttons = new ArrayList<Button>();
// The empty button to use as a buffer.
Button button;
Inside loop (where the '//Make a button' comment is):
button = new Button(this, SWT.NONE);
buttons.add(button);
Now you have a list of all the buttons, and can easily access them and make changes such as change the buttons text like so;
buttons.get(indexOfButton).setText("SomeText");
EDIT:
Seeing as you're new to swt (and I couldn't get awt/JFrame to work) here's the full code.
import org.eclipse.swt.SWT;
import org.eclipse.swt.graphics.Rectangle;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Shell;
public class ButtonTest extends Shell {
/**
* Launch the application.
* #param args
*/
// Code starts here in main.
public static void main(String args[]) {
try {
Display display = Display.getDefault();
// Creates a window (shell) called "shell"
ButtonTest shell = new ButtonTest(display);
// These two lines start the shell.
shell.open();
shell.layout();
// Now we can start adding stuff to our shell.
// The size of the window.
Rectangle bounds = shell.getBounds();
// How many rows of buttons.
int numOfRows = 5;
// How many buttons per row.
int numOfColumns = 3;
int buttonWidth = bounds.width / numOfRows;
int buttonHeight = bounds.height / numOfColumns;
Button button;
int x = 0;
int y = 0;
for(int i = 0; i < numOfColumns; i++){
for(int j = 0; j < numOfRows; j++){
button = new Button(shell, SWT.NONE);
button.setBounds(x, y, buttonWidth, buttonHeight);
x += buttonWidth;
}
x = 0;
y += buttonHeight;
}
// This loop keeps the shell from killing itself the moment it's opened
while (!shell.isDisposed()) {
if (!display.readAndDispatch()) {
display.sleep();
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* Create the shell.
* #param display
*/
public ButtonTest(Display display) {
super(display, SWT.SHELL_TRIM);
createContents();
}
/**
* Create contents of the shell.
*/
protected void createContents() {
setText("SWT Application");
setSize(800, 800);
}
#Override
protected void checkSubclass() {
// Disable the check that prevents subclassing of SWT components
}
Also, I made a little typo in my nested loop (and forgot to reset the x value to 0 after each row). It's fixed in this edit.
Also you will need to import swt for this to work.
Go here: http://www.eclipse.org/swt/ and download the latest version for your operating system, then go in eclipse, right click your project > Build Path > configure Build Path > Libraries tab > Add external JAR's > find the swt file you downloaded and click.
Sorry for such a long answer, hope it helps :D
Start with a GridLayout. Each time you need to change the seat layout, reapply the GridLayout.
Ie, if you need 100 seats, use something like, new GridLayout(20, 10)...
Personally, I'd use a GridBagLayout, but it might be to complex for the task at hand
Its a little more difficult to add/rmove new content. I would, personally, rebuild the UI and reapply the model to it.
As for the size, you may not have much control over it, as it will appear differently on different screens. Instead, you should provide means by which you can prevent the UI from over sizing the screen.
This is achievable by placing the seating pane within a JScrollPane. This will allow the seating pane to expand and shrink in size without it potentially over sizing on the screen
Take a look at
Creating a UI with Swing
Using Layout Managers
A Visual Guide to Layout Managers
Related
The simple version is that I'm drawing Graphics2D 60 times a second on a JPanel and it uses the drawstring method to create a bunch of labels. How would I go about making so I can click on those labels and have something happen?
Explanation: As it currently stands I have a system setup that says for every object in the world draw a string to the side (So I can see a list of all objects in the world). This is done with a for loop and the Graphics2D drawstring method.
The JPanel is being updated 60 times a second so this is being redrawn 60 times a second. I want to be able to click on these object labels so I can select the items, how would I go about turning them into buttons?
I messed around with JButton for awhile but it didn't seem to do me any good because whenever I added it the JPanel would go blank and only the button would render (Plus it didn't render to the right size).
More Details:
I use a
for(int I=0; I < sceneObjects.size(); I++) {
}
loop to grab every object in an object ArrayList. Each object has a String variable "Name". Before the loop class I sent an int called YPosition, and for every object the YPosition goes up by 20 so that the labels don't all stack on top of each other. I'm using the g2d.DrawString method to achieve this. But I need to be able to select the object labels.
I apologize if I forgot something in my question, let me know.
For those who are curious, the code looks exactly like this (Can't be compiled as is):
g2d.setFont(new Font("Arial", Font.PLAIN, hierarchyWidth / 26));
g2d.setColor(Color.black);
int oYPos = 20;
// For every object in existence
for(int i=0; i < engine.sceneObjects.activeObjects.size(); i++) {
GameObject theObject = engine.sceneObjects.activeObjects.get(i);
// If the scrollbar is within range of the hierarchy
// (Based on HierarchyHeight so that it's resolution friendly)
if(oYPos >= hierarchyScroll && oYPos < hierarchyScroll + hierarchyHeight) {
// If the object has no parent
if(theObject.transform.parent == null) {
g2d.drawString(theObject.name, hierarchyPosition.x + 5, hierarchyPosition.y + oYPos);
} else { // If the object has a parent
}
}
oYPos += 20;
}
// Track the last oYPos so that the scrollbar can adjust itself accordingly
lastOYPos = oYPos;
My guess would be some sort of class create for each of these labels and a Boolean stored called isSelected, and then rendering the label according to the class, but this seems a bit more complicated than I'd like to do
What is the most painless way to create an N x N grid in a JavaFX application?
The only requirements I'm looking for is that the size of the grid will always take up the same amount of space, so more squares = smaller squares. I can set colors for the squares, and I can hover over each square individually and be able to show some for each square.
I won't know 'N' until the program runs and parses through some data to figure out how many total squares I need which is when I calculate the smallest NxN grid I can use.
From what I can tell my options are:
GridPane - Using the column constraints and row constraints to generate size and possibly add properties for hovering?
TableView - A lot more options for being able to give each cell data to show when hovered over but still difficult to just add rows and columns to start with.
Rectangles - Just generate and draw each rectangle while calculating the x and y coordinates for each square. This will make it easy to do the colors and hovering but I can't see how resizing would work but I'm ok with having a specific size for my application. I'll also have to calculate the best size to make each square to fill up the grids area.
I'm not necessarily looking for someone to code a solution, but if someone has dealt with this and knows a good way I'd like to hear about it.
Don't stray away from the original ideas. Why are you looking for "painless" ways when all the methods you've given are all viable? Here's one using your rectangles. The GridMaker.SCREEN_SIZE refers to the size of the screen you must have.
public static Pane makeGrid(int n){
double width = GridMaker.SCREEN_SIZE/n;
Pane p = new Pane();
Rectangle [][] rec = new Rectangle [n][n];
for(int i=0; i<n; i++){
for(int j=0; j<n; j++){
rec[i][j] = new Rectangle();
rec[i][j].setX(i * width);
rec[i][j].setY(j * width);
rec[i][j].setWidth(width);
rec[i][j].setHeight(width);
rec[i][j].setFill(null);
rec[i][j].setStroke(Color.BLACK);
p.getChildren().add(rec[i][j]);
}
}
return p;
}
Then simply add the mouse listener to the pane if you wish to make it change color.
p.setOnMouseClicked(new EventHandler <MouseEvent> (){
#Override
public void handle(MouseEvent me){
double posX = me.getX();
double posY = me.getY();
int colX = (int)(posX / width);
int colY = (int) (posY / width);
rec[colX][colY].setFill(Color.RED);
}
});
-- Edit
1)
2) For Hover, what kind of hover effects are you looking for? You can add Hover effects onto each rectangles, if you want me to show you how, I can definitely code it for you.
I am making a program where you choose a selection sort or a merge sort using JButtons and it sorts an int array in the form of a bar graph using Graphics where each element in the array is a bar.
but for some reason the compiler isn't receiving my button presses, i have tried to use
(selection.equals(e.getSource()) in the if statement but it isnt working, am i missing something obvious or what?
public class Animation extends Canvas implements ActionListener{
JPanel panel;
JButton Selection;
JButton Merge;
boolean selection, merge;
int[] random = new int[25];
Sorter sort = new Sorter();
public Animation(){
Selection = new JButton("Selection sort");
Selection.addActionListener(this);
Selection.setActionCommand("select");
Merge = new JButton("Merge sort");
Merge.addActionListener(this);
Merge.setActionCommand("merge");
panel = new JPanel();
panel.add(Selection);
panel.add(Merge);
setBackground(Color.WHITE);
selection=false;
merge=false;
}
public void actionPerformed(ActionEvent e) {
if("select".equals(e.getActionCommand())){
selection = true;
repaint();
}
else if("merge".equals(e.getActionCommand())){
merge = true;
repaint();
}
}
public void paint (Graphics window){
Random r = new Random();
for(int i=0; i<random.length; i++){
int randomInt = r.nextInt(100) + 1;
random[i] = randomInt;
}
window.setColor(Color.MAGENTA);
if(selection==true){
for(int i=0; i< random.length-1; i++){
int smallest = i;
for(int j = i+1; j< random.length; j++){
if(random[j] < random[smallest])
smallest = j;
}
if( smallest != i) {
int least = random[smallest];
random[smallest] = random[i];
random[i] = least;
drawIt(random, window);
window.setColor(Color.WHITE);
drawIt(random, window);
window.setColor(Color.MAGENTA);
}
}
}
drawIt(random, window);
}
public void drawIt (int[] a, Graphics window1){
int x=128;
int height = 200;
for(int i=0; i<a.length; i++){
window1.drawLine(x, 200, x, height-a[i]);
window1.drawLine(x+1, 200, x+1, height-a[i]);
window1.drawLine(x+2, 200, x+2, height-a[i]);
x+=20;
}
try {
Thread.currentThread().sleep(100);
} catch(Exception ex) {
}
}
}
heres the main class to run it:
public class AnimationRunner extends JFrame{
private static final int WIDTH = 800;
private static final int HEIGHT = 250;
JButton Selection;
JButton Merge;
public AnimationRunner()
{
super("Sorting Animation");
setSize(WIDTH,HEIGHT);
Animation a = new Animation();
Merge = new JButton("Merge sort");
Selection = new JButton("Selection sort");
Merge.setSize(120, 30);
Selection.setSize(120,30);
Merge.setLocation(200, 30);
Selection.setLocation(400, 30);
this.add(Merge);
this.add(Selection);
((Component)a).setFocusable(true);
getContentPane().add(new Animation());
setVisible(true);
}
public static void main( String args[] )
{
AnimationRunner run = new AnimationRunner();
}
}
You create a button for each action in your main class and add these to your JFrame. You also create a two instances of your Animation class. One which you create, setfocusable then do nothing with. Then another which you create and add to the contentPane of the JFrame.
In your Animation constructor you again create a button for each action, this time setting the action commands. You then add these to a panel. This panel is never added to anything and so these buttons will never be seen.
The buttons you see are not the buttons that you have defined the action commands for.
Also you should avoid using setSize() and Use Layout Managers to defines the sizes of your components.
There are a series of cascading problems...
In the AnimationRunner class you create two JButtons called Merge sort and Selection sort and add these to the main frame. This is what's actually on the screen. This buttons have no listeners attached, therefore never notify any body when they are clicked...
In the Animation class you create two JBttonss called Merge sort and Selection sort and add these to panel (and instance of JPanel), which is never added to anything. This means you can never possibly click them...
You don't seem to have an understanding of how painting works in Swing and seem to be assuming that you control the paint process in some way.
Painting is controlled by the paint sub system in Swing, which schedules and performs paint cycles when and where it sees fit. This means that your paint method may be called for any number of reasons, many of which you don't control.
Remove the logic of the sort out of the paint process and place into some kind of model, whose state you can control. Then use the custom painting capabilities to render the state of the model.
paint is an inappropriate method to be using for custom painting and you should be using paintComponent. You have broken the paint chain which may prevent the component from rendering child components and/or introduce series paint artifacts into your program
Take a look at Performing Custom Painting and Painting in AWT and Swing for more details
Swing is a single threaded framework work. That means that anything that blocks the Event Dispatching Thread will prevent it from process new repaint requests or events into the system. This will cause your program to look like it's "hung". In your case, you will most likely only ever see the end result of the painting process...after a short delay.
Instead, consider using a javax.swing.Timer to introduce a safe delty and update the model each time it ticks.
Take a look at Concurrency in Swing and How to use Swing Timers for more details
Swing programs are expected to run on a variety of hardware and software platforms, all with there own notions of DPI and font rendering approaches. This makes it very difficult to accommodate your design to all the possible needs of these systems.
Swing makes this easier by providing a layout management API, which takes the fiddle work out of making these decisions. Take a look at Laying Out Components Within a Container for more details
You should also take a look at Code Conventions for the Java Programming Language, it will make it eaiser for people to read your code.
You might find this example of some benifit
I am a little new to swing. In order to learn to use the API correctly, I am designing the following project:
The project is a solving block puzzle solver sliding block puzzle similar to the rush-hour puzzles common in toy stores - https://en.wikipedia.org/wiki/Rush_Hour_(board_game) except there is no escape for a special car.
By dragging the blocks from an off board area to the board, the user specifies the starting configuration of the puzzle. The user, in the same way, specifies an ending goal configuration which dictates where some (or all) of the blocks the user specified initially must be at the end of the puzzle - the ending configuration can be specified using only SOME of the blocks, making multiple legal ending configurations.
The algorithm for solving the puzzle is already complete - I just need to design the interface and I am getting stuck. For designing the tray, I used a grid layout. Since blocks need to be entered at certain positions, I need to be able to place blocks in specific cells in the grid and move them around.
A 'block' object has four attributes - its height, width, its top row, and its left most column (ie - each block is addressed by its top left corner).
I used the suggestion here ( https://stackoverflow.com/questions/2510159/can-i-add-a-component-to-a-specific-grid-cell-when-a-gridlayout-is-used ) for the grid layout.
Right now I have only programmed to the point where java reads the puzzle from a .txt file and is supposed to display it on the screen ( I have not designed any user interactablity yet ).
First, here is the code I have written so far.
public class SolverPuzzleGUI extends JFrame {
//Specs from the puzzle.
Board initBoard;
ArrayList<Block> goalBlocks;
LinkedList<Move> moveList;
JLayeredPane layeredpane;
JPanel Board;
Dimension boardsize = new Dimension(400, 500);
JPanel[][] panelHolder = new JPanel[5][4];
public SolverPuzzleGUI(Board startBoard, ArrayList<Block> startGoalBlocks,
LinkedList<Move> startMoveList) {
this.initBoard = startBoard;
this.goalBlocks = startGoalBlocks;
this.moveList = startMoveList;
} // end constructor.
//gives the actual simulation
public void runSimulation() {
// Initalizing the main window.
setSize(500, 600);
setName("Solution");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setMinimumSize(getMinimumSize());
//Using layered pane
layeredpane = new JLayeredPane();
add(layeredpane);
layeredpane.setPreferredSize(boardsize);
layeredpane.setBackground(Color.YELLOW);
layeredpane.setVisible(true);
// adding the game tray
Board = new JPanel();
layeredpane.add(Board, JLayeredPane.DEFAULT_LAYER);
Board.setLayout(new GridLayout(5, 4));
// centering the game tray.
Board.setPreferredSize(boardsize);
Board.setMinimumSize(boardsize);
Board.setMaximumSize(boardsize);
Box box = new Box(BoxLayout.Y_AXIS);
box.add(Box.createVerticalGlue());
box.add(Board);
box.add(Box.createVerticalGlue());
add(box);
//Adding placeholders to the board for creating blocks
for (int i = 0; i < 5; i++) {
for (int j = 0; j < 4; j++) {
panelHolder[i][j] = new JPanel();
panelHolder[i][j].setBackground(Color.DARK_GRAY);
Board.add(panelHolder[i][j]);
layeredpane.setLayer(panelHolder[i][j], JLayeredPane.DEFAULT_LAYER);
panelHolder[i][j].setVisible(false);
} // end 'j' for
} // end 'i' for
ArrayList<Block> initBlocks = initBoard.getBlocks();
//int count = 0; //DEBUG
for (Block block : initBlocks) {
this.drawBlock(block);
//count++;
//if(count > 4) { break; }
} // end 'for'
Board.setBackground(Color.DARK_GRAY);
Board.setVisible(true);
setVisible(true);
} // end 'run'
private void drawBlock(Block block) {
Dimension blockSize = new Dimension(block.getWidth()*100, block.getHeight()*100);
System.out.println(blockSize.width);
System.out.println(blockSize.height);
JPanel screenBlock = new JPanel();
screenBlock.setPreferredSize(blockSize);
screenBlock.setMinimumSize(blockSize);
screenBlock.setMaximumSize(blockSize);
screenBlock.setSize(blockSize);
screenBlock.setBackground(Color.BLUE);
screenBlock.setBorder(BorderFactory.createLineBorder(Color.BLACK));
layeredpane.setLayer(screenBlock, JLayeredPane.MODAL_LAYER);
int leftRow = block.getRow();
int leftCol = block.getColumn();
panelHolder[leftRow][leftCol].setSize(blockSize);
panelHolder[leftRow][leftCol].setVisible(true);
panelHolder[leftRow][leftCol].add(screenBlock);
layeredpane.setLayer(panelHolder[leftRow][leftCol], JLayeredPane.MODAL_LAYER);
screenBlock.setVisible(true);
}// end 'drawBlock'
public static void main(String[] args) {
String file = "C:\\Users\\Tim\\Desktop\\init.from.handout.txt";
String goal = "C:\\Users\\Tim\\Desktop\\goal.2.from.handout.txt";
/*
A SolverPuzzle object is the object which actually solves the algorithm -
when the class is constructed, it takes the file path of the inital
configuration as an input, as well as the file path of the goal
configuration. It has the following fields:
A 'board' object which specifies the inital configuration of the board.
It contains an ArrayList of Block objects(Remember block objects store
the height and width of the block, as well as the address of the
top left corner of block) which specify the starting
blocks, an ArrayList of EmptySpace objects which specify the empty
spaces on the board, an ArrayList of Move objects, which contain
the legal moves of the configuration, and the height and width of
the tray (in this application, the tray will always be 5 x 4).
An ArrayList of Block objects which specify the ending configuration.
A LinkedList of Move objects which specify the shortest possible
list of Moves which brings the configuration to a position which
satisfies the goal position. A Move object has three fields -
The block object being moved, and the row and column of the
top left corner of the block in the new position.
*/
SolverPuzzle test;
try { test = new SolverPuzzle(file, goal); }
catch (IOException ex) {
System.out.println("IOException");
return;
}
Board testBoard = test.getStartBoard();
ArrayList<Block> testGoalBlocks = test.getGoalBlocks();
LinkedList<Move> testMoveSolution = test.getMoveList();
// testing the gui
SolverPuzzleGUI testGUI = new SolverPuzzleGUI(testBoard, testGoalBlocks,
testMoveSolution);
testGUI.runSimulation();
}
} // end class 'SolverPuzzleGUI'
Here's the current output vs desired output.
http://imgur.com/a/ykXXP
So specifically, I have two questions:
1 - Why is the image only showing the top left corners of the blocks instead of the whole block?
2 - Is it better to continue using the GridLayout or switch to GridBagLayout?
Thanks
GridBagLayout would definitely be suitable for want you want to do. For example, you can expand components to envelop more than one column or row - just like what you want to do. Check out the java tutorials for how to use them.
A key point to remember when using GridBagLayoutis that you need to reset the Constraints after each component, assuming that they're unique to that particular component.
Also - I can't discern what you mean by only showing the top-left - it looks likes its showing the whole thing to me...
I'm creating a user interface for a game that I have to do as a class project, and needless to say I'm not experienced with Swing.
I did learn about actionevents and whatnot for simple button pushes, but in those cases I knew how many buttons would be on screen. Here, I need to create a board with an arbitrary number of tiles, which will be represented as buttons in Swing. I need to push a button and "move" my character from one tile to another, so I need to call a method on one tile object to remove the player from that tile, and then add it to another tile.
So my question is, given that the number of buttons is generated at runtime (and stored in a 2d array) how can I make an actionlistener that is able to distinguish between each unique button?
Set all your buttons to the same handler:
ActionListener a = new ActionListener() {
#Override
public void actionPerformed(ActionEvent evt) {
if (evt.getSource() == buttons[0][0]) {
}
// etc
// common handling
}
};
for (int i = 0; i < height; ++i)
for (int j = 0; j < width; ++j)
buttons[i][j].addActionListener(a);