Don't mind the use of the Window Insets, but pay more attention to the use of the ScreenInsets, which is saved locally as Insets insets; I print the insets.bottom, and for every monitor the taskbar height shows up, even though the taskbar is only located on the first monitor.
The monitor insets on my second monitor should all be zero, but yet it acts as if the taskbar is located on both monitors. Setting the window to full size in the monitor the window is currently located on works, except it leaves room for the taskbar regardless which monitor are use it in.
From my understanding of the Toolkit.getScreenInsets(GraphicsConfiguration), it should return the correct insets for the specific GraphicsConfiguration you pass in, yet I'm passing in each GraphicsDevice's GraphicsConfiguration and getting the same results back.
JFrame window;
public void setSizeToFullScreen()
{
GraphicsEnvironment ge=GraphicsEnvironment.getLocalGraphicsEnvironment();
GraphicsDevice[] screenDevices=ge.getScreenDevices();
Point p=window.getLocationOnScreen();
for(int i=0;i<screenDevices.length;i++)
{
Rectangle2D b=screenDevices[i].getDefaultConfiguration().getBounds();
if(SMath.getMath().doesRectangleContainPoint(b.getX(), b.getY(), b.getWidth(), b.getHeight(), p.getX(),p.getY()))
{
Insets insets = Toolkit.getDefaultToolkit().getScreenInsets(screenDevices[i].getDefaultConfiguration());
System.out.println("Monitor: "+i+": task bar height: "+insets.bottom);
this.setSize(b.getWidth()+1 -(insets.right+insets.left)-(this.window.getInsets().left+this.window.getInsets().right), b.getHeight()+1-(insets.top+insets.bottom)-(this.window.getInsets().top+this.window.getInsets().bottom));
this.setLocation(b.getX()+insets.left+window.getInsets().left, b.getY()+insets.top+window.getInsets().top);
return;
}
}
}
My question is, in Java, how can we figure out which monitor actually has the taskbar, or the better question, how can we get the correct monitor insets for each monitor in Java.
Re: "..., yet it acts as if the taskbar is located on both monitors".
I found the following:
Referring to Windows->Control Panel->Appearance and Personalization->
Display->Screen Resolution:
When gs[0] (= the display shown with a "1" inside a circle in the Control Panel window above) has the Toolbar, the reported Insets are correct.
I.e., they are reported to be = 0 for the no-Toolbar screen and = 49 for the screen that has the Toolbar.
When any other gs[x] has the Toolbar, the reported Insets are wrong :-(. I.e., they are reported to be = 49 for all screens.
In my application, I want "JDialog dialog0" to always appear 500 to the right of the lower-left corner of my "big" display, and "JFrame frameBalloonHerderGui" to always appear in the upper-left corner of my "small" display.
I want the JDialog to have a fixed size in the lower-left corner of my "big" display, and the JFrame should pretty much fill the "small" display it's in.
I did give the graphicsConfiguration for the display I wanted each JDialog/JFrame to appear in to their constructors. Alas, that is not enough to allow the Insets to be correct.
To accomplish the positioning above, I wrote a function that I call for my JDialog and JFrame as follows:
// I'll omit the creation of the grapicsConfiguration for now.
JDialog dialog0 = new JDialog( gc);
ScreenAndTaskBarHeights h = getThisComponentsScreensTaskBarHeight( dialog0);
final int myWidth = 1170;
final int myHeight = 800;
final int myScreenXInset = 500;
final int myScreenYInset = 10;
dialog0.setBounds(
h.screenOriginX + myScreenXInset,
h.screenOriginY + h.screenHeight - myHeight - h.taskBarHeight - myScreenYInset,
myWidth, myHeight);
dialog0.setVisible( true);
// I'll omit the creation of the grapicsConfiguration for now.
JFrame frameBalloonHerderGui = new JFrame( gc);
ScreenAndTaskBarHeights h =
getThisComponentsScreensTaskBarHeight( frameBalloonHerderGui);
final int myWidth = 1695;
final int myScreenInset = 10;
frameBalloonHerderGui.setBounds(
h.screenOriginX + myScreenInset,
h.screenOriginY + myScreenInset,
myWidth, h.screenHeight - (myScreenInset * 2) - h.taskBarHeight);
frameBalloonHerderGui.setVisible( true);
The workaround I found is that the screenSize.x & .y = (0,0) for the display that has the TaskBar, and some big positive or negative numbers for the other displays.
The function below successfully implements this workaround. I also made a simple class so I could pass multiple values back to the caller as shown above.
// Add additional data members here to your liking.
static class ScreenAndTaskBarHeights
{
int screenOriginX = -1;
int screenOriginY = -1;
int screenHeight = -1;
int taskBarHeight = -1;
ScreenAndTaskBarHeights()
{
}
void setValues(
int newScreenOriginX, int newScreenOriginY,
int newScreenHeight, int newTaskBarHeight)
{
screenOriginX = newScreenOriginX;
screenOriginY = newScreenOriginY;
screenHeight = newScreenHeight;
taskBarHeight = newTaskBarHeight;
}
}
static ScreenAndTaskBarHeights
getThisComponentsScreensTaskBarHeight( Component c)
{
ScreenAndTaskBarHeights screenAndTaskBarHeights =
new ScreenAndTaskBarHeights();
GraphicsConfiguration gc = c.getGraphicsConfiguration();
Insets scnMax = Toolkit.getDefaultToolkit().getScreenInsets( gc);
// This should be the TaskBar height specific to the gc that we
// passed in, but it's not :-(.
//
// int taskBarHeight = scnMax.bottom;
//
// However, this seems to be a successful workaround:
//
Rectangle screenSize = gc.getBounds();
boolean thisScreenHasTheToolbar =
(screenSize.x == 0 && screenSize.y == 0);
// Change scnMax.bottom to catch wherever you're worried that the
// TaskBar may be lurking.
//
screenAndTaskBarHeights.setValues(
screenSize.x, screenSize.y, screenSize.height,
(thisScreenHasTheToolbar) ? scnMax.bottom : 0);
return screenAndTaskBarHeights;
}
Related
I am building a Minesweeper clone, and my startNewGame() method works well. In that method, I also change the field size if the difficulty has been changed.
Here is how it looks on
easy (9x9):
And here is how it looks on intermediate (16x16).
It also works well if I have 20x20, 30x30, etc. The problem is that if I change the board to 30x16 (expert), it looks like this. It seems like it starts stretching the buttons after a certain aspect ratio for some reason. I set the minefield JPanel's preferred size to [16 * x, 16 * y] (each cell is 16x16).
Why are my buttons stretching and how can I prevent that from happening?
Here is my startNewGame() method (keep in mind that most things are static so their declarations aren't here):
public static void startNewGame()
// Resets and starts a new Game.
{
timer.stop();
timerLabel.setText("00:00");
clicks = 0;
int newGridLength, newGridHeight, newNumOfMines;
if (difficulties[0].isSelected())
{
newGridLength = 9;
newGridHeight = 9;
newNumOfMines = 10;
}
else if (difficulties[1].isSelected())
{
newGridLength = 16;
newGridHeight = 16;
newNumOfMines = 40;
}
else if (difficulties[2].isSelected())
{
newGridLength = 30;
newGridHeight = 16;
newNumOfMines = 99;
}
else
{
newGridLength = 9;
newGridHeight = 9;
newNumOfMines = 10;
}
GRID_LENGTH = newGridLength;
GRID_HEIGHT = newGridHeight;
NUM_OF_MINES = newNumOfMines;
remainingMines = NUM_OF_MINES;
remainingMinesLabel.setText("" + remainingMines);
buttonGrid.clear();
cellGrid.clear();
frame.remove(gridPane);
gridPane = new JPanel();
gridPane.setLayout(new GridLayout(GRID_LENGTH, GRID_HEIGHT));
initializeGrid(gridPane);
gridPane.setPreferredSize(new Dimension(CELL_SIZE * GRID_LENGTH, CELL_SIZE * GRID_HEIGHT));
frame.add(gridPane, BorderLayout.CENTER);
frame.pack();
}
I read more into other layouts and converted my program to GridBagLayout, and it's working as intended now.
Result:
Expert (30x16)
gridPane.setLayout(new GridLayout(GRID_LENGTH, GRID_HEIGHT));
The GridLayout uses
new GridLayout(rows, columns)
as the parameters.
You are passing the parameters in the wrong order.
Note the easiest to create a GridLayout is to only specify a single non-zero value.
So I would use:
gridPane.setLayout(new GridLayout(0, GRID_LENGTH));
This will specify 30 columns.
Now as you add components to the grid it will wrap every 30 components.
I have a JDesktopPane where I add and show a JInternalFrame called ListarEmpleado.java. From that ListarEmpleado.java I open another JInternalFrame called InformacionEmpleado.java doing click in a button. I have a equation to locate InformacionEmpleado.java in the middle of the JDesktopPane when it is opened.
This is the button event (I code in Netbeans):
private void masInformacionActionPerformed(java.awt.event.ActionEvent evt) {
InformacionEmpleado verDetalle = new InformacionEmpleado(this.cedulaSeleccionada);
escritorio = getDesktopPane();
escritorio.add(verDetalle);
int width = verDetalle.getParent().getWidth();
int width1 = verDetalle.getWidth();
int height = verDetalle.getParent().getHeight();
int height1 = verDetalle.getHeight();
verDetalle.setLocation(width / 2 - width1 / 2, height / 2 - height1/ 2 - 10);
verDetalle.setVisible(true);
}
The problem is when the line verDetalle.setVisible(true); is executed, InformacionEmpleado.java is located in the middle perfectly and I don't have problems with it, but if I have ListarEmpleado.java maximized, it returns to its initial size (does not stay maximized). Why does this happen and how can I fix it?
Thanks a lot!
I have JLabel which I would like to change its size while I resize the window. When JLabel contains String which is too big, the String should be shortened, with right part visible and adds dots on the left hand side of the String.
My JLabel is inside innerPanel which is a header in middlePanel which is added to outerPanel. So when I resize window I use listener on outerPanel in that way:
outerPanel.addComponentListener(new ComponentListener() {
#Override
public void componentResized(ComponentEvent evt) {
int width = ((JPanel) evt.getSource()).getWidth();
windowSize = width;
refresh();
}
// [...] other not used override methods
});
refresh() repaints view and creates new middlePanel where is called class which creates innerPanel where is located my JLabel:
Public class InnerPanel extends JPanel {
private int maxSize;
String string = "<VERY_LONG_STRING>";
private static final int DEFAULT_INDEND_PIXEL = 70;
public InnerPanel(int windowSize) {
maxSize = windowSize - DEFAULT_INDENT_PIXEL;
createPanel();
}
private createPanel() {
// [...] gridbag and GridBagConstraints implementation
String shortString = countString();
JLabel label = new JLabel(shortString);
add(label,gc);
}
private String countString() {
int index = 0;
boolean toBig = true;
StringBuilder sb = new StringBuilder(string);
while(toBig) {
Rectangle2d rect = // [...] code which creates rectangle around text from sb.toString()
// I have no access to repo at home but if it's important I can paste it tomorrow
if(rect.getWidth() > maxSize)
sb.deleteCharAt(0);
else
toBig = false;
}
return sb.toString();
}
}
That's works fine in general, bacause it do resize JLabel in one step when I enlarge window in width. But the problem is appear when I try to reduce the window in width. In this case componentResized() calculate width step by step (and it's called multiple times), gradually decreases width by some amount of pixels till it reach real window size. It's behave in that way even thow I change window size in one step from maximum size to 800. Whole process is so slow, that it takes around a second to fit string to window size. So it looks bit like an animation.
The problem is very rare to me, bacause width in componentResized() method is calculeted step by step only when I assign windowSize variable.
When I give windowSize fixed size like for example 500 - componentResized() is called only onces - with correct width indicated real window size (!!) - and there's no its step by step decrease!
It's look like width variable which is assigned by ((JPanel) evt.getSource()).getWidth() knows that windowSize is used to dynamically change size of JLabel component even before first call of refresh() method.
If anyone have an idea what is going on here - I will be very appreciate for help.
You may be able to adapt one of the approaches shown here to better effect. As shown here, the ellipsis is supplied by the label's UI delegate via a call to SwingUtilities2.clipString(), which appends the clipString. Rather than re-invent the label UI, use TextLayout to determine the required geometry, prepend the ellipsis, and handle the alignment in a table or list renderer, as shown here.
I want to reduce the height of my autocomplete field.How to go about it
heres my code
HorizontalFieldManager hfm = new HorizontalFieldManager();
LabelField lbl = new LabelField(" Name: ");
final AutoCompleteField TextField1 = new AutoCompleteField(filterLst)
{
public int getPreferredWidth()
{
return Display.getWidth()/2;
}
public void sublayout(int maxWidth, int maxheight)
{
super.sublayout(getPreferredWidth(), getPreferredHeight());
setExtent(getPreferredWidth(), getPreferredHeight());
}
};
hfm.add(lbl);
hfm.add(TextField1);
add(hfm);
The picture below is how it looks. I want it to look the same size as my editfields that have been used for other labels.
Here's my code for editfield
//Add box next to field for containing input
HorizontalFieldManager hfm1 = new HorizontalFieldManager();
LabelField lbl1 = new LabelField(" Amount: ");
final EditField TextField2 = new EditField()
{
boolean _drawFocus = false;
protected void layout(int maxWidth, int maxHeight)
{
super.layout(Math.min(maxWidth, 300), Math.min(maxHeight, 30));
}
protected boolean keyChar(char ch, int status, int time)
{
if (CharacterUtilities.isDigit(ch) || (ch == Characters.BACKSPACE))
{
return super.keyChar(ch, status, time);
}
return true;
}
protected void drawFocus(Graphics graphics,boolean on)
{
_drawFocus = on;
super.drawFocus(graphics, on);
_drawFocus = false;
}
protected void paint(Graphics g)
{
if ( _drawFocus )
{
super.paint(g);
return;
}
g.clear();
g.drawRect(0,0, 50, 50);
int oldColor = g.getColor();
g.setColor(Color.WHITE);
g.fillRect(0, 0, this.getPreferredWidth(), this.getPreferredHeight());
g.setColor(oldColor);
g.drawRect(100, 100, 50, 50);
super.paint(g);
}
};
TextField2.setBorder(BorderFactory.createRoundedBorder(new XYEdges(6,6,6,6)));
hfm1.add(lbl1);
hfm1.add(TextField2);
add(hfm1);
I would like to have the size of autocompletefield used for name same as other fields.Please help.
Thanks
One thing that's probably causing you trouble is that EditField is what people normally think of as a Field. AutoCompleteField, however, is handled more like a Manager. It wants to be a Manager, of course, because it (probably) contains an EditField, but then will also contain another child Field which shows the autocomplete options dynamically.
(Non-Manager) Field and Manager subclasses handle layout a little differently, so I found that trying to fix this with the normal getPreferredHeight() and layout() and sublayout() didn't work that well for me.
So, what I did was twofold:
First, I tried to mimic the decoration of the default AutoCompleteField with your EditField subclasses. It's not perfect. If you want them to look exactly alike, you might need to write custom paint() methods for both. You stated the problem as simply wanting to resize the fields, so I thought that was good enough.
Second, since the AutoCompleteField seems to contain a child EditField (at least logically ... I'm not sure if it's implemented that way), I decided to try to get that EditField to choose its own size, in a way that matched the normal EditFields. To do that, I controlled all fields' height by simply setting the same Font on each.
My changes to your code:
final int fontSize = 24; // pick whatever you like here
final int pad = 2;
final int margin = 2;
I removed the code in your edit field's layout() method that was attempting to control height, since ... as I said, I didn't have success setting the autocomplete field's height in a similar way. I just changed your edit field's layout() to a very standard implementation:
final EditField TextField2 = new EditField()
{
boolean _drawFocus = false;
protected void layout(int maxWidth, int maxHeight)
{
super.layout(getPreferredWidth(), getPreferredHeight());
}
Then, I set the padding on your edit field, because it looks to me like AutoCompleteField uses a pad of 2 pixels (on a 5.0 Storm2). You may not care, for this UI, but it also appears to have a margin of 2 pixels.
TextField2.setPadding(pad, pad, pad, pad);
TextField2.setMargin(margin, margin, margin, margin);
Then, I set the same font for all your fields. It doesn't have to be the default font. Just make them all the same. This step is what seemed to dictate the visible size of the rounded rectangle field drawn by AutoCompleteField ... setting the font.
Font font = Font.getDefault().derive(Font.PLAIN, fontSize);
TextField1.setFont(font);
TextField2.setFont(font);
After that, the edit fields and autocomplete fields should be a consistent height. I tested this on a 5.0 9550. Since the pad and margin values were determined experimentally, I can totally believe that those values (e.g. 2 pixels) could change on different devices. You may have to experiment a bit.
I have never been able to figure this one out; the usual suspects don't work.
Given:
FileDialog dlg=null;
dlg=new FileDialog(owner,"Select File to Load",FileDialog.LOAD);
dlg.setFile(null);
dlg.setVisible(true);
is there any way to get that dialog centered?
A key point is that at setVisible(), the calling thread is blocked until the dialog is dismissed; and any positioning prior to that seems to be ignored.
The below solution works for SWT, probably it can do the trick for AWT as well...
As it shows the dialog in left top corner of the current shell, a quick-and-dirty solution is to create a new, well-positioned and invisible shell and to open FileDialog from it. I got an acceptable result with the following code:
import org.eclipse.swt.SWT;
import org.eclipse.swt.graphics.Rectangle;
import org.eclipse.swt.widgets.Dialog;
import org.eclipse.swt.widgets.FileDialog;
import org.eclipse.swt.widgets.Shell;
public class CenteredFileDialog extends Dialog {
protected Shell shell;
public FileDialog dialog;
private int width = 560; // WinXP default
private int height = 420;
public CenteredFileDialog(Shell parent, int style) {
super(parent, style);
shell = new Shell(getParent(), SWT.APPLICATION_MODAL);
dialog = new FileDialog(shell, style);
}
public Object open() {
shell.setSize(width, height);
Rectangle parentBounds = getParent().getBounds();
shell.setLocation(
parentBounds.x + (parentBounds.width - width) / 2,
parentBounds.y + (parentBounds.height - height) / 2);
Object result = dialog.open();
shell.dispose();
return result;
}
}
The class can be used this way:
CenteredFileDialog saveDialog = new CenteredFileDialog(getShell(), SWT.SAVE);
saveDialog.dialog.setFilterExtensions(new String[] { "*.txt" });
saveDialog.dialog.setFilterNames(new String[] { "Text (*.txt)" });
...
String f = (String)saveDialog.open();
if ( f != null ) {
name = f;
recentPath = saveDialog.dialog.getFilterPath();
}
The class only partially solves the problem for Windows platform (On MacOS the dialog is screen-centered anyway; on Linux I did not test) - first time the dialog appears centered relatively to the parent shell (which is what we need), and "remembers" its absolute position on the screen. By subsequent calls it always pops up in the same place, even if the main application window moved.
Despite the oddity, from my perspective the new behaviour is definitely better than the default unprofessionally looking top-left docking of the dialog.
Appears that this may still be a bug.... see last line of this (though its dated 2003)
http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4333836
I threw this together
FileDialog fd = new FileDialog(f, title, FileDialog.LOAD);
Dimension dim = Toolkit.getDefaultToolkit().getScreenSize();
int w = fd.getSize().width;
int h = fd.getSize().height;
int x = (dim.width-w)/2;
int y = (dim.height-h)/2;
System.out.println("Dialog location: " + fd.getLocation().toString());
fd.setLocation(x, y);
System.out.println("Dialog location: " + fd.getLocation().toString());
fd.setVisible(true);
And my output was:
Dialog location: java.awt.Point[x=0,y=0]
Dialog location: java.awt.Point[x=840,y=525]
But the screen was still in the top left corner
Try this code: dlg.setLocationRelativeTo(null);
Using Java 7, Eclipse 4.4.1 and Ubuntu 14.04 I was able to find a solution for centering AWT FileDialog.
I was determined to find a solution because Apple recommends using awt.FileDialog over Swing's JFileChooser for a more native look and feel.
The trick is to give your FileDialog instance a size before setting its location.
Use the bounds of the contentPane of your main application frame to calculate the distance of the left corner Point (minX, minY) of FileDialog from the contentPane's center Point.
Then set the location of your FileDialog to this calculated Point, et voilá ... centered.
final FileDialog fileDialog = new FileDialog(applicationFrame,
"Choose a file", FileDialog.LOAD);
/* Lots of code to be able to center an awt.FileDialog on screen... */
Rectangle rect = applicationFrame.getContentPane().getBounds();
/*
* Making sure FileDialog has a size before setVisible, otherwise
* left corner's distance from contentPane center cannot be found.
*/
fileDialog.pack();
fileDialog.setSize(800, 600);
fileDialog.validate();
double width = fileDialog.getBounds().getWidth();
double height = fileDialog.getBounds().getHeight();
double x = rect.getCenterX() - (width / 2);
double y = rect.getCenterY() - (height/ 2);
/* Could be new Point(x, y) */
Point leftCorner = new Point();
leftCorner.setLocation(x, y);
fileDialog.setLocation(leftCorner);
fileDialog.setVisible(true);