I have many JTable but they populate data by using another public class. I have passed the entire JTable by its constructor. ok works fine. Now for some reason, i need to override some function ... so i will do it before populate data....
#Override
public boolean getScrollableTracksViewportWidth() {
}
#Override
public void doLayout() {
}
#Override
public void columnMarginChanged(ChangeEvent e) {
}
But my JTable object is already created which is already pass... i can't overide like this...
new JTable(1,5){
#Override
public void columnMarginChanged(ChangeEvent e) {
}
}
may be its so simple basic..i don't know how override a component object's basic functions which is already created...
I design a function...Now its working for my issue ....
void getAutoResizeTable(final JTable table) {
table.getColumnModel().addColumnModelListener(new TableColumnModelListener() {
#Override
public void columnSelectionChanged(ListSelectionEvent lse) {
}
#Override
public void columnAdded(TableColumnModelEvent tcme) {
}
#Override
public void columnRemoved(TableColumnModelEvent tcme) {
}
#Override
public void columnMoved(TableColumnModelEvent tcme) {
}
#Override
public void columnMarginChanged(ChangeEvent ce) {
TableColumn resizingColumn = table.getTableHeader().getResizingColumn();
if (resizingColumn != null) {
resizingColumn.setPreferredWidth(resizingColumn.getWidth());
}
if (hasExcessWidth(table)) {
table.setAutoResizeMode(JTable.AUTO_RESIZE_SUBSEQUENT_COLUMNS);
} else {
table.setAutoResizeMode(JTable.AUTO_RESIZE_OFF);
}
}
protected boolean hasExcessWidth(JTable table) {
return table.getPreferredSize().width < table.getParent().getWidth();
}
});
}
Related
I'm trying to use the MVC Pattern for the first time.
And I'm not sure if i do it the right way:
Main Class:
public class DBEditorMain
{
public static void main(String[] args)
{
DBEditorController control = new DBEditorController(new DBEditorView());
}
}
DBEditorController constructor:
public DBEditorController(DBEditorView view)
{
this.view = view;
addListeners ();
view.setVisible (true);
}
DBEditorController addListeners():
private void addListeners()
{
view.addWindowListener (new WindowAdapter ()
{
#Override
public void windowClosing(WindowEvent e)
{
terminate ();
}
});
view.addActionListeners (this);
}
DBEditorView Constructor:
public DBEditorView()
{
super ("Database");
setSize (800, 600);
setResizable (false);
initGUI ();
}
DBEditorView addActionListeners():
public void addActionListeners(ActionListener l)
{
closeButton.setActionCommand ("close");
saveButton.setActionCommand ("save");
closeButton.addActionListener (l);
saveButton.addActionListener (l);
}
DBEditorController actionPerformed():
#Override
public void actionPerformed(ActionEvent e)
{
switch (e.getActionCommand ())
{
case ("save"):
save();
break;
case ("close"):
terminate();
break;
}
}
I think i did it right since the View and Model (not implemented yet) have no references to the Controller or to each other.
Is this a good start or have I missed something.
I know this is a dumb "question" ._.
Like the title says, i need to know if someone is using a combobox.
i.e. when the box is dropped down.
Is there any method to get this? Maybe an actionlistener?
Use JComboBox#addPopupMenuListener():
comboBox.addPopupMenuListener(new PopupMenuListener()
{
#Override
public void popupMenuWillBecomeVisible(PopupMenuEvent e)
{
// ...
}
#Override
public void popupMenuWillBecomeInvisible(PopupMenuEvent e)
{
// ...
}
#Override
public void popupMenuCanceled(PopupMenuEvent e)
{
// ...
}
});
I'd like to build a standard JTable but with all rows spanned on one specific column. So that column has to contain only one cell with a JTextPane as its renderer.
Do you know any simply way to do that?
NB: no third part software required.
Thanks.
Triggered by #MvG idea of some kind of overlay here's a proof-of-concept using JLayer (added to core in jdk7, for earlier versions, use JXLayer in SwingLabs which is very similar)
The basic ingredients:
a LayerUI which manages a textArea in its glassPane
a custom layoutManager which sizes/locates the textArea over a column
some listeners which force a re-layout of the glassPane
It's surprisingly straightforward to at least make it work. There are some rough edges, though:
as always, navigation in the table: when table has focus, its cell selection is moved under the textArea. Probably needs a custom selectionModel
during the move of a column, the table rows under the column are visible
?? probably another bunch of devils, after all we are confusing the ui :-)
Some code:
public static class RowSpanUI extends LayerUI<JTable> {
public static String COLUMN_TO_SPAN_KEY = "Table.columnToSpan";
private JLayer layer;
private JTextArea area;
#Override
public void installUI(JComponent c) {
super.installUI(c);
this.layer = (JLayer) c;
installTextArea();
installListeners();
}
#Override
public void doLayout(JLayer<? extends JTable> l) {
super.doLayout(l);
l.getGlassPane().doLayout();
}
private void installTextArea() {
area = new JTextArea(10, 20);
layer.getGlassPane().setBorder(BorderFactory.createLineBorder(Color.RED));
layer.getGlassPane().setLayout(new ColumnLayoutManager(this));
layer.getGlassPane().add(area);
layer.getGlassPane().setVisible(true);
}
public JTable getView() {
return (JTable) layer.getView();
}
public int getViewColumnToSpan() {
Object clientProperty = getView().getClientProperty(COLUMN_TO_SPAN_KEY);
if (clientProperty instanceof Integer) {
return getView().convertColumnIndexToView((int) clientProperty);
}
return -1;
}
/**
* Install listeners to manually trigger a layout of the glassPane.
* This is incomplete, just the minimum for demonstration!
*/
protected void installListeners() {
ComponentListener compL = new ComponentListener() {
#Override
public void componentShown(ComponentEvent e) {
doLayout(layer);
}
#Override
public void componentResized(ComponentEvent e) {
doLayout(layer);
}
#Override
public void componentMoved(ComponentEvent e) {
doLayout(layer);
}
#Override
public void componentHidden(ComponentEvent e) {
// TODO Auto-generated method stub
}
};
layer.addComponentListener(compL);
TableColumnModelListener columnL = new TableColumnModelListener() {
#Override
public void columnRemoved(TableColumnModelEvent e) {
doLayout(layer);
}
#Override
public void columnMoved(TableColumnModelEvent e) {
doLayout(layer);
}
#Override
public void columnMarginChanged(ChangeEvent e) {
doLayout(layer);
}
#Override
public void columnAdded(TableColumnModelEvent e) {
doLayout(layer);
}
#Override
public void columnSelectionChanged(ListSelectionEvent e) {
}
};
getView().getColumnModel().addColumnModelListener(columnL);
}
}
public static class ColumnLayoutManager implements LayoutManager {
private RowSpanUI ui;
public ColumnLayoutManager(RowSpanUI ui) {
this.ui = ui;
}
#Override
public void layoutContainer(Container parent) {
Component child = parent.getComponent(0);
child.setBounds(getColumnBounds());
}
#Override
public Dimension preferredLayoutSize(Container parent) {
return ui.getView().getSize();
}
protected Rectangle getColumnBounds() {
int viewColumn = ui.getViewColumnToSpan();
if (viewColumn < 0) {
return new Rectangle();
}
Rectangle r = ui.getView().getCellRect(0, viewColumn, false);
r.height = ui.getView().getHeight();
return r;
}
#Override
public Dimension minimumLayoutSize(Container parent) {
return preferredLayoutSize(parent);
}
#Override
public void addLayoutComponent(String name, Component comp) {
}
#Override
public void removeLayoutComponent(Component comp) {
}
}
// usage
JTable table = new JTable(myModel);
table.putClientProperty(RowSpanUI.COLUMN_TO_SPAN_KEY, 2);
JLayer layer = new JLayer(table, new RowSpanUI());
The rendering of a JTable, including the clipping to the cell rectangle, is buries deep inside the user interface implementations of the pluggable look and feel in question. Changing stuff there is going to be messy business, and highly dependent on the actual JFC implementation.
So instead I'd suggest drawing the cells of those roes any way you like, and having another transparent pane on top of the table to overlay those areas with the spanned content you describe. Still messy, probably quite a bit of work, but more likely to be portable.
i have 2 frames: parent and child. I want to do the following:
when parent frame gets activated or deiconified, child frame does the same thing.
private void attachListeners()
{
if (parentFrame != null)
{
parentFrame.addComponentListener(this);
parentFrame.addWindowListener(new ViewEventAdapter(this));
}
#Override
public void viewActivated()
{
// show it when the parent is activated
if (!childFrame.isVisible())
{
childFrame.setVisible(true);
parentFrame.toFront();
}
}
But this causes infinite loop of flickering. If i remove toFront(), I cant switch focus to parent frame. I just need to somehow switch focus correctly.
Listener code:
public class ViewEventAdapter implements WindowListener, InternalFrameListener
{
private MyViewListener listener = null;
public ViewEventAdapter(MiaViewListener inListener)
{
listener = inListener;
}
#Override
public void windowActivated(WindowEvent inE)
{
listener.viewActivated();
}
#Override
public void windowClosed(WindowEvent inE)
{
listener.viewClosed();
}
#Override
public void windowClosing(WindowEvent inE)
{
listener.viewClosing();
}
#Override
public void windowDeactivated(WindowEvent inE)
{
listener.viewDeactivated();
}
#Override
public void windowDeiconified(WindowEvent inE)
{
listener.viewDeiconified();
}
#Override
public void windowIconified(WindowEvent inE)
{
listener.viewIconified();
}
#Override
public void windowOpened(WindowEvent inE)
{
listener.viewOpened();
}
#Override
public void internalFrameActivated(InternalFrameEvent inE)
{
listener.viewActivated();
}
#Override
public void internalFrameClosed(InternalFrameEvent inE)
{
listener.viewClosed();
}
#Override
public void internalFrameClosing(InternalFrameEvent inE)
{
listener.viewClosing();
}
#Override
public void internalFrameDeactivated(InternalFrameEvent inE)
{
listener.viewDeactivated();
}
#Override
public void internalFrameDeiconified(InternalFrameEvent inE)
{
listener.viewDeiconified();
}
#Override
public void internalFrameIconified(InternalFrameEvent inE)
{
listener.viewIconified();
}
#Override
public void internalFrameOpened(InternalFrameEvent inE)
{
listener.viewOpened();
}
}
public interface MyViewListener
{
/**
* Called when a view is activated
*/
public void viewActivated();
/**
* Called when a view is closed
*/
public void viewClosed();
/**
* Called when a view is closing
*/
public void viewClosing();
/**
* Called when a view is deactivated
*/
public void viewDeactivated();
/**
* Called when a view is deiconified
*/
public void viewDeiconified();
/**
* Called when a view is iconified
*/
public void viewIconified();
/**
* Called when a view is opened
*/
public void viewOpened();
}
Please help. Thanks in advance.
Don't use 2 JFrames.
Instead the parent should be a JFrame and the child should be a non-modal JDialog. When you create the dialog you specify the frame as the parent and you get this behaviour by default.
This is the way most applications are designed.
How should I detect that column moved action is finished in JTable? I've added columnModeListener to my column model but the problem is columnMoved method is called every time a column moves (by certain pixels). I don't want this behavior. I just want to detect when the column dragging is finished.
columnModel.addColumnModelListener(new TableColumnModelListener() {
public void columnAdded(TableColumnModelEvent e) {
}
public void columnRemoved(TableColumnModelEvent e) {
}
public void columnMoved(TableColumnModelEvent e) {
//this is called so many times
//I don't want this, but something like column moved finished event
System.out.println("Moved "+e.getFromIndex()+", "+e.getToIndex());
}
public void columnMarginChanged(ChangeEvent e) {
}
public void columnSelectionChanged(ListSelectionEvent e) {
}
});
I hope it is clear what I'm looking for. Thanks.
This is what I ended up doing. I know it is dirty, but it fits for what I'm looking:
boolean dragComplete = false;
apTable.getTableHeader().addMouseListener(new MouseAdapter() {
#Override
public void mouseReleased(MouseEvent e) {
if (dragComplete) {
System.out.println("Drag completed");
}
dragComplete = false;
}
});
columnModel.addColumnModelListener(new TableColumnModelListener() {
public void columnAdded(TableColumnModelEvent e) {
}
public void columnRemoved(TableColumnModelEvent e) {
}
public void columnMoved(TableColumnModelEvent e) {
dragComplete = true;
}
public void columnMarginChanged(ChangeEvent e) {
}
public void columnSelectionChanged(ListSelectionEvent e) {
}
});
Here's an inner class I use to determine when the column ordering has changed. Note that the user may not have let go of the mouse at this point, so the dragging may continue further.
private class ColumnUpdateListener implements TableColumnModelListener {
int lastFrom = 0;
int lastTo = 0;
private void verifyChange(int from, int to) {
if (from != lastFrom || to != lastTo) {
lastFrom = from;
lastTo = to;
///////////////////////////////////////
// Column order has changed! Do something here
///////////////////////////////////////
}
}
public void columnMoved(TableColumnModelEvent e) {
verifyChange(e.getFromIndex(), e.getToIndex());
}
public void columnAdded(TableColumnModelEvent e) {
verifyChange(e.getFromIndex(), e.getToIndex());
}
public void columnRemoved(TableColumnModelEvent e) {
verifyChange(e.getFromIndex(), e.getToIndex());
}
public void columnMarginChanged(ChangeEvent e) {}
public void columnSelectionChanged(ListSelectionEvent e) {}
}
It's worked well for me.
This might be a better approach:
table.setTableHeader(new JTableHeader(table.getColumnModel()) {
#Override
public void setDraggedColumn(TableColumn column) {
boolean finished = draggedColumn != null && column == null;
super.setDraggedColumn(column);
if (finished) {
onColumnChange(table); // Handle the event here...
}
}
});
This is what works for me (both column movements and margin resizes):
I extend the table and override the columnMoved and columnMarginChanged
methods in the following way:
... first add some variables for state keeping
private int lastMovementDistance = 0;
private boolean bigMove = false;
private boolean resizeBegan = false;
...
#Override
public void columnMarginChanged(ChangeEvent e) {
super.columnMarginChanged(e);
if (isShowing()){
resizeBegan = true;
}
}
#Override
public void columnMoved(TableColumnModelEvent e) {
super.columnMoved(e);
//this will be set to 0 when the column is dragged
//to where it should begin if released
lastMovementDistance = Math.abs(getTableHeader().getDraggedDistance());
if (e.getFromIndex() != e.getToIndex()){
//note, this does not guarantee that the columns will be eventually
//swapped - the user may move the column back.
//but it prevents us from reacting to movements where
//the user hasn't even moved the column further then its nearby region.
//Works for me, because I don't care if the columns stay the same
//I only need the updates to be infrequent and don't want to miss
//changes to the column order
bigMove = true;
}
}
... then in the constructor of my table i do this:
public MyTable(){
...
getTableHeader().addMouseListener(new MouseAdapter(){
public void mouseReleased(MouseEvent evt) {
if (bigMove && lastMovementDistance == 0 ){
//react! the tables have possibly switched!
}
else if (resizeBegan){
//react! columns resized
}
resizeBegan = false;
bigMove = false;
}
});
...
}
It is kinda like a hack, but it works for me.
Nice answer on your own question ashokgelal. Just a little improvement I think. Your code also trigger on single click on the header. Using one more flag you can prevent the 'dragComplete' trigger when the column haven't really changed.
Modified code:
boolean mDraggingColumn = false;
boolean mColumnCHangedIndex = false;
tblObjects.getTableHeader().addMouseListener(new MouseAdapter() {
#Override
public void mouseReleased(MouseEvent e) {
if (mDraggingColumn && mColumnCHangedIndex) {
System.out.println("Column changed");
}
mDraggingColumn = false;
mColumnCHangedIndex = false;
}
});
tblObjects.getColumnModel().addColumnModelListener(new TableColumnModelListener() {
#Override
public void columnAdded(TableColumnModelEvent e) {}
#Override
public void columnRemoved(TableColumnModelEvent e) {}
#Override
public void columnMoved(TableColumnModelEvent e) {
mDraggingColumn = true;
if (e.getFromIndex() != e.getToIndex()) {
mColumnCHangedIndex = true;
}
}
#Override
public void columnMarginChanged(ChangeEvent e) {}
#Override
public void columnSelectionChanged(ListSelectionEvent e) {}
});
If I understand you correctly, maybe you want to look at the mouse listeners. Maybe the MOUSE_RELEASED event?
All answers fail at one use-case: if the table is in a layout filling up the entire window, then resizing the window will resize the table and thus its columns. By watching for mouse events on the column headers, we fail to receive the event when the user resize the window.
I looked at the JTable&friends source-code, and the columnMarginChanged() method is always called in a sub-sub-sub...-function called by JTable.doLayout().
Then, my solution is to watch for doLayout() calls that trigger at least one columnMarginChanged().
In fact, columnMarginChanged() is called for every columns.
Here is my solution:
private class ResizableJTable extends JTable {
private TableColumnModelListener columnModelListener;
private boolean columnsWereResized;
#Override
public void setColumnModel(TableColumnModel columnModel) {
if (getColumnModel() != null) {
getColumnModel().removeColumnModelListener(columnModelListener);
columnModelListener = null;
}
if (columnModel != null) {
columnModelListener = new TableColumnModelListener() {
public void columnSelectionChanged(ListSelectionEvent e) {
// Nothing to do
}
public void columnRemoved(TableColumnModelEvent e) {
// Nothing to do
}
public void columnMoved(TableColumnModelEvent e) {
// Nothing to do
}
public void columnMarginChanged(ChangeEvent e) {
columnsWereResized = true;
}
public void columnAdded(TableColumnModelEvent e) {
// Nothing to do
}
};
columnModel.addColumnModelListener(columnModelListener);
}
super.setColumnModel(columnModel);
}
#Override
public void doLayout() {
columnsWereResized = false;
super.doLayout();
if (columnsWereResized) {
onColumnsResized();
}
}
/**
* Sub-classes can override this method to
* get the columns-were-resized event.
* By default this method must be empty,
* but here we added debug code.
*/
protected void onColumnsResized() {
int[] columnSizes = getColumnSizes();
String sizes = "";
for (int i : columnSizes) {
sizes += i + " ";
}
System.out.println("COLUMNS RESIZED: [ " + sizes + "]");
}
protected int[] getColumnSizes() {
TableColumnModel columnModel = getTableHeader().getColumnModel();
int columnCount = columnModel.getColumnCount();
int[] columnSizes = new int[columnCount];
for(int i = 0; i < columnCount; i++) {
TableColumn column = columnModel.getColumn(i);
columnSizes[i] = column.getWidth();
}
return columnSizes;
}
}