drawing boxes in java - java

I have wrote a program that simulates memory allocation with first fit and best fit algorithms .
Now I want to associate my program with a drawing of set of boxes representing available memory segments
Before Allocation
After Allocation
So it just redraws but resizes one box and colors it ... What is the easiest way to do so ?
I have a set of boxes with different sizes that will be drawn dynamically according to input when the user does some action one of the boxes will be resized and recolored and so on.

I think this is best approached using graphics.
Instantiate a BufferedImage of a size to fit all boxes.
Get a Graphics instance by calling either of getGraphics() or createGraphics().
For each memory block:
Call Graphics.setColor(Color) according to allocation status, then..
Graphics.fillRect(int,int,int,int) or fillPolygon(Polygon) to draw the memory block.
If needed, use an AffineTransform to scale the sizes. This would require a Graphics2D object to draw on.

Use JPanel add JLabels like 0verbose but the layout to go with in my opinion is BoxLayout or GridBagLayout.
With FlowLayout you would have to make sure the size of the container is of a proper width to place one component under another, as by default it places components in a row.
From Java tutorial about FlowLayout "The FlowLayout class puts components in a row, sized at their preferred size. If the horizontal space in the container is too small to put all the components in one row, the FlowLayout class uses multiple rows."

Use a JPanel as container with vertical FlowLayout BoxLayout, and add to it a JLabel for each memory block.

If the memory blocks can be rendered all the same size, a JComponent (or even easier a JProgressBar) could be used to represent each memory block. Those could then be put into a GridLayout or BoxLayout to organize the placement. E.G.
MemoryAllocation.java
import java.awt.*;
import javax.swing.*;
import java.util.Random;
class MemoryAllocation {
public static JProgressBar getMemoryBlock(int full) {
JProgressBar progressBar = new JProgressBar(
SwingConstants.VERTICAL, 0, 100);
progressBar.setValue(full);
progressBar.setPreferredSize(new Dimension(30,20));
return progressBar;
}
public static void main(String[] args) {
SwingUtilities.invokeLater( new Runnable() {
public void run() {
JPanel memoryView = new JPanel(new GridLayout(0,10,1,1));
Random random = new Random();
for (int ii=0; ii<200; ii++) {
int amount = 100;
if (random.nextInt(5)==4) {
amount = 100-random.nextInt(75);
}
memoryView.add( getMemoryBlock(amount) );
}
JOptionPane.showMessageDialog(null, memoryView);
}
});
}
}
Screen Shot

Related

Java JFrame Boundaries

I'm trying to write a code that does the following:
If I click on the String C(JLabel) whose starting position is (100,100), the String moves WITHIN the boundaries of JFrame. The code itself wasn't hard to implement but I'm having issues with setting the (x,y) for JLabel so that any Part of the String "C" doesn't get cut off.
import javax.swing.*;
import java.awt.event.*;
import java.awt.*;
public class adfadf extends JFrame{
JLabel text = new JLabel("C");
Container container = getContentPane();
public adfadf(){
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
container.setLayout(null);
MyMouseListener mml = new MyMouseListener();
text.addMouseListener(mml);
text.setLocation(100,100);
text.setSize(30,30);
add(text);
setSize(400,400);
setVisible(true);
}
public static void main(String[] args) {
new adfadf();
}
}
class MyMouseListener extends MouseAdapter{
#Override
public void mouseClicked(MouseEvent e){
JLabel text = (JLabel)e.getSource();
int x = (int)(Math.random()*(400-30));
int y = (int)(Math.random()*(400-30));
text.setLocation(x,y);
}
}
How should I change
int x = (int)(Math.random()*(400-30));
int y = (int)(Math.random()*(400-30));
in order to achieve what I want?
First, understanding that a JFrame is much more complex then it seems
To start with, a JFrame has a JRootPane, that contains the contentPane and JMenuBar and glassPane
This is further complicated by the fact the window's decorations are actually painted WITHIN the visible bounds of the frame, meaning that the visible area available to your content is actually smaller than the frame's size.
You can have a look at How can I set in the midst?, Graphics rendering in title bar and How to get the EXACT middle of a screen, even when re-sized for more details and examples of this.
But how does this help you? Well, now you know that you have a space of less than 400x400 to display your label in, but how much?
The simple solution is to stop using "magic" numbers, and take a look at something which is been used by the frame, the contentPane. The contentPane is managed by the the JFrame (via the JRootPane) so that it sits within the frame decorations, so you could do something more like...
JLabel text = (JLabel)e.getSource();
int width = getContentPane().getSize().width;
int height = getContentPane().getSize().height;
int x = (int)(Math.random()*(width-30));
int y = (int)(Math.random()*(height-30));
text.setLocation(x,y);
The reason for looking at the contentPane in this instance is simply because, that's the container that the label is actually added to.
This is one of the reasons why we suggest you don't use "magic" numbers, but look at the actual known values at the time you need them.

Why does the JTable not show the Jtable heading even when added to JScrollPane?

import javax.swing.*;
import javax.swing.border.*;
import javax.swing.table.TableColumn;
import java.awt.*;
import static java.awt.GraphicsDevice.WindowTranslucency.*;
import java.awt.Checkbox;
import java.awt.Paint;
import java.awt.Toolkit;
import java.awt.event.*;
public class Main extends JPanel {
static Object [][] Services = {{"Google.exe","Chickeaen.exe","Crp.exe"}};
static String [] ColNames = {"Processes:","Crolly:","Haler:"};
static JFrame Fram = new JFrame();
static JTextField CBox = new JTextField();
static JTable Tabs = new JTable(Services,ColNames);
JScrollPane ScrollArea = new JScrollPane();
static JButton ExitB = new JButton();
Dimension ScreenSize = new Dimension(Toolkit.getDefaultToolkit().getScreenSize());
Border BlackLineB = BorderFactory.createLineBorder(new Color(50,50,50));
public Main() {
Fram.setTitle("Jared Console");
Fram.setUndecorated(true);
Fram.setVisible(true);
Fram.setDefaultCloseOperation(Fram.EXIT_ON_CLOSE);
Fram.setResizable(false);
Fram.setSize((int)Math.round(ScreenSize.getWidth()*0.45),(int)Math.round(ScreenSize.getHeight()*0.33));
Fram.setBackground(new Color(0,0,0,150));
Fram.add(this);
CBox.setSize((int)Math.round(Fram.getWidth()*0.80),(int)Math.round(Fram.getHeight()*0.25));
CBox.setBackground(new Color(255,255,255));
CBox.setBorder(BorderFactory.createCompoundBorder(BlackLineB,BorderFactory.createEmptyBorder(0,20,0,0)));
CBox.setLocation((int)Math.round(Fram.getWidth()*0.1),(int)Math.round(Fram.getHeight()*0.70));
CBox.setFont(new Font("Arial",Font.BOLD,20));
CBox.setVisible(true);
ScrollArea.setSize((int)Math.round(Fram.getWidth()*0.80),(int)Math.round(Fram.getHeight()*0.50));
ScrollArea.setLocation((int)Math.round(Fram.getWidth()*0.10),(int)Math.round(Fram.getHeight()*0.10));
ScrollArea.setBorder(BlackLineB);
ScrollArea.setLayout(null);
ScrollArea.setVisible(true);
Tabs.setSize((int)Math.round(Fram.getWidth()*0.995),(int)Math.round(Fram.getHeight()*0.995));
Tabs.setLocation((int)Math.round(Fram.getWidth()*0.003),(int)Math.round(Fram.getHeight()*0.005));
Tabs.setFillsViewportHeight(true);
Tabs.setBackground(new Color(255,255,255));
this.add(CBox);
this.add(Tabs);
this.add(ExitB);
ScrollArea.add(Tabs);
this.add(ScrollArea);
this.setBorder(BorderFactory.createLineBorder(new Color(50,50,50),5));
this.setLayout(null);
this.setBackground(new Color(0,0,0));
this.setVisible(true);
}
public void paintComponent(Graphics Gla) {
Paint Plat = new GradientPaint(0f, 0f, new Color(0, 40, 0, 0), 0.0f, Fram.getHeight(), new Color(0, 0, 0, 150), true); //Made 200 equal to Fram Background Alpha.
Graphics2D Quo = (Graphics2D)Gla;
Quo.setPaint(Plat);
Quo.fillRect(0, 0, Fram.getWidth(), Fram.getHeight());
}
public static void main(String[] args) {
Main CScreen = new Main();
GraphicsEnvironment GE = GraphicsEnvironment.getLocalGraphicsEnvironment(); // Have to study lines 57,58 and 59
GraphicsDevice GD = GE.getDefaultScreenDevice();
boolean CheckTransL = GD.isWindowTranslucencySupported(PERPIXEL_TRANSLUCENT);
if (!CheckTransL) {
System.out.println("PERPIXEL TRANSLUCENT NOT SUPPORTED - LOL UPDATESCRUB!");
System.exit(0);
};
}
}
Why does the JTable not show the Jtable heading even when added to JScrollPane?
Also the Console shows a error message at first then quickly goes away and launches the program? So yea I'd like to know what's wrong with this and also can you can note me of some bad habits in this program such as the way it's being typed.
Problems
null layout. Avoid using null layouts, pixel perfect layouts are an illusion within modern ui design. There are too many factors which affect the individual size of components, none of which you can control. Swing was designed to work with layout managers at the core, discarding these will lead to no end of issues and problems that you will spend more and more time trying to rectify. See Laying Out Components Within a Container for more details
Over use of static. static is not your friend and you should avoid using it. It is not a cross object communication mechanism and over use like this will burn you
You don't actually wrap the JTable in JScrollPane
Breaking the paint chain by not calling super.paintComponent, this is going to produce a series of wonderful paint artifacts. See Painting in AWT and Swing and Performing Custom Painting for more details about how painting works in Swing
You might like to have a read through Code Conventions for the Java TM Programming Language, it will make it easier for people to read your code and for you to read others
All interactions, creations and modifications to the UI should be done from within the context of the Event Dispatching Event, to reduce the risk of potential race conditions, dead locks and rendering artifacts. See Initial Threads for more details
Toolkit.getDefaultToolkit().getScreenSize() is a bad indicator for the viewable space of a screen, it does not take into account OS specific elements, like the dock or task bar, which could have your application appearing under them (and I really, really, REALLY hate it when that happens). Use appropriate layout managers and pack to pack the window around the content. You can then use JFrame#setLocationRelativeTo and pass it null and it will center the frame in the screen
JScrollPane issue...
The simply solution would be to use JScrollPane's constructor to pass it the reference of the JTable...
static JTable Tabs = new JTable(Services,ColNames);
JScrollPane ScrollArea = new JScrollPane(Tabs);
But, then you do this later in your code...
this.add(Tabs);
This will remove the table from the scroll pane to add it to you panel, as a component can only have a single parent.
Another option would be to specifiy the scroll pane's viewport's view component...
this.add(CBox);
//this.add(Tabs);
this.add(ExitB);
//ScrollArea.add(Tabs);
ScrollArea.setViewportView(Tabs);
this.add(ScrollArea);
You should never add components directly to a scroll pane (or it's underlying viewport), they have their own internal layout management functionality going on. Instead, you need to supply the component as the "view" to the JViewport
Take a look at How to Use Scroll Panes for more details.
First of all you should add a JTable to the ViewPort of the a JScrollPane in order to JTableHeader could be visible.
After that you should not add your JTable to both the JScrollPane and also the underlying container. You should:
add the JTable to the ViewPort of the JScrollPane.
add the JScrollPane to the underlying container.
and remove the line that add the JTable to the container explicitly.
Good Luck.

GridLayout hgap vgap "not working" on JPanel?

JPanel grid = new JPanel();
GridLayout layout = new GridLayout (6,7,0,0);
grid.setLayout (layout);
slot = new ImageIcon ("");
for (int x = 0; x < 42; ++x)
{
slotbtn = new JButton(slot);
slotbtn.setContentAreaFilled (false);
//slotbtn.setBorderPainted (false);
slotbtn.setBorder (BorderFactory.createEmptyBorder (0,0,0,0));
slotbtn.setFocusPainted (false);
grid.add(slotbtn);
}
This is the output I get:
I am creating a 6x7 grid. The output I need is for there to be no space in between the rows and columns, everything should be compressed together. I tried pack and it didn't work. What am I doing wrong?
-- I tried FlowLayout but I had to resize the frame and I have other buttons on the frame so I don't think I'd prefer resizing it to make the buttons fit in their proper places.
-- I placed this JPanel inside another jpanel(which uses borderlayout and contains two other panels) and I placed it at the center, the two other panels North and South.
this issue because you divide the grid (the whole size of grid) to 7*6 so if you re-size the window you will see this gaps changed so if you wan't to remove this gab
calculate the size of the window (ex: width = 7* width of your image , hight = 6*hight of your mage)
or re-size your image
JButton employs a margin property to provide additional padding to the content area of the button, you could try using...
slotbtn.setMargin(new Insets(0, 0, 0, 0));
I would also try using something like slotbtn.setBorder(new LineBorder(Color.RED)); to determine if the spacing is from the button, icon or layout
GridLayout will also provide each cell with equal amount of space, based on the available space to the container, this means that the cell may increase beyond the size of the icon.
While a little more work, GridBagLayout would (if configured properly) honour the preferred size of each component.
Have a look at How to use GridBagLayout for more ideas.
I get no margins using your code, with any image I use. Check your image. And maybe post a runnable example replicating the problem. Maybe there's something going on you're not showing us. I'd start by checking the image for margins. Check it against this. If it still has margins, than its your image. Also, Don't set the size to anything! You may be stretching the panel unnecessarily, which will cause the gaps. Also if there an of your other panels are larger than the grip panel, it will also cause it to stretch. But take all your set(Xxx)sizes out and see what happens. Just pack()
import java.awt.GridLayout;
import javax.swing.*;
public class TestButtonGrid {
public TestButtonGrid() {
ImageIcon icon = new ImageIcon(getClass().getResource("/resources/stackoverflow3.png"));
JPanel panel = new JPanel(new GridLayout(6, 7));
for (int i = 0; i < 42; i++) {
JButton slotbtn = new JButton(icon);
slotbtn.setContentAreaFilled(false);
//slotbtn.setBorderPainted (false);
slotbtn.setBorder(BorderFactory.createEmptyBorder(0, 0, 0, 0));
slotbtn.setFocusPainted(false);
panel.add(slotbtn);
}
JFrame frame = new JFrame();
frame.add(panel);
frame.pack();
frame.setVisible(true);
}
public static void main(String[] args) {
new TestButtonGrid();
}
}

JLabels to be resized in a GridLayout

I have a very simple Java program (see below). The GridLayout has 20 rows and 4 columns. As you know the elements are supposed to be added horizontally by (GridLayout) definition. However, I get the two elements (labels) placed one above the other, vertically.
I colored them and realised the labels take up the whole row, hence the vertical effect. But then I also used setSize(5,5) with each to make them smaller, however they still take up the whole row. Any advice as to why this happens and how to fix/set smaller size/etc?
public class Sam extends JFrame {
public JButton btn_arr;
public Container c;
public JLabel[] lbl = new JLabel[20];
public Sam()
{
c = getContentPane();
c.setLayout(new GridLayout(20,4));
lbl[1] = new JLabel("Column1");
c.add(lbl[1]);
lbl[2] = new JLabel("Column2");
c.add(lbl[2]);
show();
}
public static void main(String[] args)
{
Sam x = new Sam();
x.setVisible(true);
x.setSize(7500,4500);
}
}
You're only adding two components to the grid so they will fill it up. You need to add more components to the grid as placeholders so that it can place the original JLabels in their proper place, perhaps empty JLabels or JPanels.
As an aside, you should avoid setting the size of any Swing component. Your current size of 7500, 4500 is a bit on the large size.
As a second aside, perhaps you want to use a JTable instead here.
Edit: if you want a GridLayout with 4 columns and variable number of rows, use 0 for your GridLayout row constant:
c.setLayout(new GridLayout(0, 4));
e.g.,
import java.awt.*;
import javax.swing.*;
public class Sam extends JFrame {
public static final int COLUMN_COUNT = 4;
public JButton btn_arr;
public Container c;
public JLabel[] lbl = new JLabel[COLUMN_COUNT];
public Sam() {
c = getContentPane();
c.setLayout(new GridLayout(0, COLUMN_COUNT));
for (int i = 0; i < lbl.length; i++) {
lbl[i] = new JLabel("Column " + (i + 1));
c.add(lbl[i]);
}
}
public static void main(String[] args) {
Sam x = new Sam();
x.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
x.pack();
x.setLocationRelativeTo(null);
x.setVisible(true);
// x.setSize(7500,4500);
}
}
But still I wonder if a JTable wouldn't work better here.
One thing to keep in mind with the GridLayout is it that it is designed to cover the entire containing panel sizing the cells as equally as possible, and elements added to the cells will be expanded to fill the entire cell. So as the cell sizes change, the labels will also change in size. Effectively grid cells force an expansion/contraction in both X and Y direction of all contained elements.
One way to prevent that from happening if you must use the GridLayout is to not add the labels directly to the container that uses the GridLayout, but instead put each label inside a JPanel that uses a FlowLayout (the default) that you can set alignment of either Left, Middle or Right, then add that JPanel to the Grid container. The JPanel will be resized but it will not change the size of the Label.
Or use the GridBagLayout manager. More complex, but once you understand it, it makes life easier. But as Hovercraft mentioned, if what you are trying to do is create a grid with column headers, a JTable might be a better option.

How to accurately get the coordinates of a JFrame's contents?

This is my JFrame code:
public static int width = 800;
public static int height = 600;
public static void main(String[]args){
JFrame frame= new JFrame("RETRO");
frame.add(new Screen());
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(width,height);
frame.setVisible(true);
frame.setResizable(false);
}
Basically when I want something to move to the edge of the screen, I have to add extra pixels for it work (I'm guessing because it includes the frame itself instead of just the display size? However the origins work fine (x=0, y=0)). Example:
public double getX(){
if(x<0)
x=0;
if(x+getImage().getWidth(null)>Game.width-6)
x=Game.width-6-getImage().getWidth(null);
return x;
}
public double getY(){
if(y<0)
y=0;
if(y+getImage().getHeight(null)>Game.height-26)
y=Game.height-26-getImage().getHeight(null);
return y;
}
Is there a way around this? I don't think the JFrame would be the same size on everyone's computer, not to mention the guesswork. Rather have it much neater and flexible by using an exiting variable from the JFrame component. Does there exist something like a frame.getDisplayWidth and Height function?
Don't set the size of the frame, set the preferred size of the contents.
Pack the frame
Get co-ordinates according to the position in the content
How do you set a 'preferred size' for the contents? I'm using a Screen class (extended JPanel) for rendering.
screen.setPreferredSize(new Dimension (600,400));
frame.setContentPane(screen);
frame.pack();
// frame will now be the size it needs to display the contents
// and the frame's own decorations (title bar etc.)
// ..now add a nice tweak.
frame.setMinimumSize(frame.getSize());
It seems you want to do something like a full screen app. JFrame's setDecorated(false) would do away with title and borders. setBounds does the sizing.
Instead of explicitly setting the size of the frame, try to set the preferred size of the content (in your case, the Screen object).
Also, just in case you need to find out the actual size of the frame decorations (title bar and borders), there is no need for guess work -- you can get this information by calling JFrame.getInsets()

Categories

Resources