1

Background

I'm building a system in Java that generates a GUI at runtime using a predetermined tree of values describing component classes, layout, and data binding's, where each non-fringe node is the name of some component, e.g

gui
+-- txtDist
|   +-- class: "text"
|   +-- binding: "dx"
|   +-- xy: [0,0]
|   +-- wh: [1,1]
+-- txtTime
|   +-- class: "text"
|   +-- binding: "dt
|   +-- xy: [0,1]
|   +-- wh: [1,1]
+-- txtV
|   +-- class: "text"
|   +-- binding: "v"
|   +-- xy: [1,0]
|   +-- wh: [1,2]
+-- btnCalc
|   +-- class: "button"
|   +-- binding: "fnCalcV" //a function that assigns the quotient of dx and dt to v
|   +-- label: "Calc. Velocity"
|   +-- xy: [0,2]
|   +-- wh: [1,1]
+-- btnClear
|   +-- class: "button"
|   +-- binding: "fnClear" //a function which sets variables to 0
|   +-- label: "Clear"
|   +-- xy: [1,2]
|   +-- wh: [1,1]

Where the binding values are names of variables on a kdb+ server. The resulting GUI looks something like this:

Runtime GUI

When the system receives the tree, it creates the GUI using the description but doesn't immediately populate the components with the data. This is due to the design of the system which lets it update the components in real-time as their bound variables are changed on the server; when the server is queried or updated, the updated variable is sent over a ServerSocket and placed on an update queue, which then invokes notifyObservers on the data model objects that represent the kdb+ variables. The components, which are observing their respective models based on the binding tree values, are then given the new data to display.

Problem

Upon rendering the GUI from the tree, the JFrame.setVisible(true) is called, and the components all send queries to the server asking for their data. The data objects are sent back one by one on the update queue, and the observers are notified subsequently.

At this point, the frame is tiny since the components are visible, but empty. At the moment I'm calling JFrame.pack() after each update message is consumed by the data model objects, which in itself is a waste of resources, but it makes sure that once the components have been populated they all are displayed properly.

BUT

If the user resizes the Frame to make it bigger, and then the data on the server is updated, the JFrame.pack() method is invoked again when the new data is added to the update queue, so the frame's resize will be undone. I'm wondering if there's an equivalent to pack() that only fits the frame if the current size doesn't fit all of the data. 

Community
  • 1
  • 1
adnan_252
  • 411
  • 2
  • 4
  • 10

2 Answers2

2

Normally when you dynamically update the components on a visible GUI you use:

panel.add(...);
panel.revalidate();
panel.repaint();

However this will not resize the frame to show all the components.

After invoke the above code you could invoke getPreferredSize() and getSize() on you panel. Then if the preferred width/height is less than the actual width/height you could manually invoke pack() on the frame.

camickr
  • 321,443
  • 19
  • 166
  • 288
  • @camickr's recommendation is sound; this [example](http://stackoverflow.com/a/5760093/230513) dynamically invoke's `pack()` on the enclosing `Window`. – trashgod Jul 14 '14 at 15:40
0

A not very elegant solution would be:

void packExpand(JFrame frame)
{
    Dimension oldDim = frame.getSize();
    frame.pack();
    Dimension newDim = frame.getSize();
    frame.setSize(oldDim.width > newDim.width?oldDim.width:newDim.width, oldDim.height > newDim.height?oldDim.height:newDim.height);
}

However this has the upside of being able to "pack" (expand) only one dimension while preserving the other.

A better solution would check the frame.getPreferredSize() values before resizing anything, however I've found some cases where this wasn't working properly, so check by yourself if it works for you. The pack() source code might help.

DSquare
  • 2,458
  • 17
  • 19