PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : JTree anzeige ändern?


AHF
2003-12-18, 15:20:50
grüße,

ich lasse mir in meinem programm diverse objekte via JTree anzeigen. dabei habe ich diese objekte als UserObject des DefaultMutableTreeNode gesetzt.


DefaultMutableTreeNode childNode;
Object child = ...;

childNode = new DefaultMutableTreeNode(child);
treeModel.insertNodeInto(childNode, parentNode,
parentNode.getChildCount());


dummerweise wird als text der nodes immer das komplette UserObject angezeigt, also javax.media...@adresse. dieser eintrag ist mir aber zu lang. ich möchte etwas anderes kürzeres anzeigen, ohne das UserObject zu ändern. geht das?

HellHorse
2003-12-18, 16:35:47
toString() overriden oder eigener TreeCellRenderer scheiben.

AHF
2003-12-18, 19:49:15
danke für den dezenten hinweis.

andere frage, selbes thema: wenn ich im JTree einen node auswaehle und mit F2 den namen aendere, wird automatisch das UserObject ueberschrieben. ich moechte stattdessen, dass er das UserObject nicht veraendert, sondern nur den anderen Namen anzeigt und ihn mir ausgibt. die loesung muss irgendwie im TreeModelListener liegen...

edit: hat sich erledigt...

AHF
2003-12-19, 21:51:06
weiteres problem (MouseListener):

ich möchte beim drücken eines buttons, dass eine funktion sooft hintereinander ausgeführt wird, bis ich ihn wieder loslasse.

mousePressed(MouseEvent e) funktioniert bei mir da leider genauso wie mouseClicked(MouseEvent e), also klicken -> ausführen, wieder klicken -> erneut ausführen.
ich möchte aber klicken -> ausführen, gedrückt halten -> ausführen, ausführen, ausführen..., loslassen -> stop. mit while komme ich da leider in eine endlosschleife...

HellHorse
2003-12-20, 00:07:21
Idee:
eine Variable ob geloopt werden soll
Maus gedrückt -> variable = true, while loop über Variable starten, der immer die Methode aufruft
Maus losgelassen -> variable = false, loop stoppt

Problem: 2 Threads ("Maus gedrückt" und "Maus losgelassen") greiffen darauf zu. Daher solltest du den Zugriff darauf synchronisieren. Aber lesen oder schreiben eines primiten typs (wie bool) sind atomar. Daher sollte es reichen die Variable als transient zu deklarieren.
Eventuell kannst du ja auch einen eigenen Thread starten, der loopt so dass der "Maus geclickt" Thread früher terminiert. Das loslassen der Maus kann ihn auffordern zu sterben oder pennen schicken, je nach dem wie oft so was vorkommt.

AHF
2003-12-20, 23:12:50
das mit dem loop habe ich schon versucht. ich habe in einer while schleife mit e.getID() die art des MouseEvents abgefragt.


public void mousePressed(MouseEvent e)
{
while(e.getID() == e.MOUSE_PRESSED)
{
machwas();
}
}

führte leider zu einer endlosschleife. auch mit einer globalen boolean variable komme ich zu dem selben ergebnis.

das problem ist, dass die methode mouseReleased(MouseEvent e) niemals zum zuge kommt und die variable auch nicht auf false gesetzt werden kann. transient machte das ganze nur noch schlimmer.

eine andere lösung als threads gibt es wohl nicht? da müsste ich mich nämlich erst einarbeiten (und das feature mit der gedrückten maustaste ist nur ein 'nice to have' und kein 'unbedingt notwendig').

trotzdem, danke für deine hilfe.

da fällt mir ein, dass ich gestern eigentlich zwei fragen stellen wollte, dies aber im eifer des gefechts wohl vergessen habe.

folgendes:
drei textfelder und eine checkbox, in jedes kann text reingeschrieben werden. sobald die checkbox angeklickt ist, sollen sie synchronisiert werden. egal in welches der drei textfelder man was schreibt, es soll in den anderen beiden auch erscheinen.
die lösung scheint einfach: alle drei textfelder mit textlistenern versehen und dann jeweils den inhalt in die beiden anderen schreiben. soweit so gut.
doch dummerweise springen dann die textlistener der anderen felder an und versuchen diese wiederum zu synchronisieren, mit dem ergebnis einer netten endlosschleife. lässt sich dieses problem auch wieder nur über threads lösen?

HellHorse
2003-12-21, 01:04:20
Scheint als wären die Window Events threadsafe, dh es wird immer zuerst das monitor lock auf den entsprechenden listener geholt (denk dir die mousePressed, mouseClicked,... alle als synchronized). So kann es natürlich nicht funktioneren, da der "Maus gedrückt" den monitor lock nicht aufgibt, und "Maus losgelassen" ewig wartet.
Also musst du einen neuen Thread aufmachen

public class PressFrame extends JFrame {

public PressFrame() {
super();
this.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
this.initLayout();
this.pack();
}

private void initLayout() {
Container contentPane = this.getContentPane();
contentPane.setLayout(new BorderLayout());
JButton button = new JButton("Drück mich doll!");
button.addMouseListener(new PressListener(5000));
contentPane.add(button, BorderLayout.CENTER);
}

public static void main(String[] args) {
Frame frame = new PressFrame();
frame.setVisible(true);
}
}

public class PressListener extends MouseAdapter {
private SynchronizedBoolean isLoop;

private Thread thread;

private Runnable command;

private final ReentrantLock mutex;

public PressListener(Runnable command) {
this.mutex = new ReentrantLock();
this.isLoop = new SynchronizedBoolean(false, mutex);
this.thread = new Thread(new Worker());
this.command = command;
}

public PressListener(final int sleepTime) {
this(new Runnable(){
public void run() {
System.out.println("im run loop");
try {
Thread.sleep(sleepTime);
} catch (InterruptedException e) {
}
}
});
}

public void mousePressed(MouseEvent e) {
try {
this.mutex.acquire();
this.isLoop.set(true);
if (!this.thread.isAlive()) {
this.thread = new Thread(new Worker());
this.thread.start();
}
} catch (InterruptedException e1) {
} finally {
this.mutex.release();
}
}

public void mouseReleased(MouseEvent e) {
this.isLoop.set(false);
}

private class Worker implements Runnable {
public void run() {
while(isLoop.get()) {
PressListener.this.command.run();
}
System.out.println("End of run()"); //nur zur Kontrolle
}
}
}


Zweites Problem:
Sexy wäre ein Direktorobjekt, und dann ein Key statt ein TextListener. Tönt lustig, werde gleich mal was basteln.

update:
etwa so

public class FieldsFrame extends JFrame {
private TextFeldDirector director;

public FieldsFrame() {
super();
this.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
this.initLayout();
this.pack();
}

private void initLayout() {
JPanel contentPane = (JPanel) this.getContentPane();
GridBagLayout layout = new GridBagLayout();
GridBagConstraints constraints = new GridBagConstraints();
contentPane.setLayout(layout);

director = new TextFeldDirector();

constraints.gridx = 0;
constraints.gridy = 0;
constraints.weightx = 1.0;
constraints.weighty = 0.0;
constraints.anchor = GridBagConstraints.FIRST_LINE_START;
constraints.fill = GridBagConstraints.BOTH;
constraints.insets = new Insets(0, 0, 5, 0);
JCheckBox checkBox = new JCheckBox(new SynchronizeAction());
checkBox.setSelected(false);
layout.setConstraints(checkBox, constraints);
contentPane.add(checkBox);

for (int i = 0; i < 3; ++i) {
++constraints.gridy;
JTextField textField = new JTextField(20);
director.addTextField(textField);
textField.addKeyListener(new Notifyer());
layout.setConstraints(textField, constraints);
contentPane.add(textField);
}
JPanel emptyPanel = new JPanel();
++constraints.gridy;
constraints.weighty = 1.0;
layout.setConstraints(emptyPanel, constraints);
contentPane.add(emptyPanel);

contentPane.setBorder(BorderFactory.createEmptyBorder(5, 5, 0, 5));
}

public static void main(String[] args) {
Frame frame = new FieldsFrame();
frame.setVisible(true);
}

private class Notifyer extends KeyAdapter {
public void keyTyped(KeyEvent e) {
director.charTyped(e.getKeyChar(), (JTextField) e.getSource());
}
}

private class SynchronizeAction extends AbstractAction {
private static final String ACTION_COMMAND = "synchronize-command";
private static final String NAME = "Textfelder synchronisieren";
private static final String SHORT_DESCRIPTION = "synchronisiert die Textfelder";
private static final String LONG_DESCRIPTION =
"Wenn sie das auswählen, wird jeder Buchstabe, den sien in ein Textfeld "+
"tippen, automatisch in den anderen auch getippt.";

public SynchronizeAction() {
super(NAME);
this.putValue(Action.SHORT_DESCRIPTION, SHORT_DESCRIPTION);
this.putValue(Action.LONG_DESCRIPTION, LONG_DESCRIPTION);
this.putValue(Action.ACTION_COMMAND_KEY, ACTION_COMMAND);
}

public void actionPerformed(ActionEvent e) {
JCheckBox source = (JCheckBox) e.getSource();
director.setSynchronize(source.isSelected());
}
}
}

public class TextFeldDirector {
private boolean isSynchronize;

private Set textFields;

public TextFeldDirector() {
this.isSynchronize = false;
this.textFields = new HashSet();
}

public void addTextField(JTextField textField) {
this.textFields.add(textField);
}

public void charTyped(char c, JTextField originator) {
if (this.isSynchronize) {
Iterator textFieldsIterator = this.textFields.iterator();
while (textFieldsIterator.hasNext()) {
JTextField nextField = (JTextField) textFieldsIterator.next();
if (nextField != originator) {
String text = nextField.getText();
nextField.setText(text + c);
}
}
}
}

public void setSynchronize(boolean synchronize) {
isSynchronize = synchronize;
}
}

In der Form wird ein getippter Buchstabe am Ende einfach angehäng, auch wenn der Cursor nicht am Ende war.
Ganz hässlich ist es auch, wenn man Text rauslöscht.
Aber jetzt ist erst mal Zeit für's Bett.

update2(besser spät als nie):
Es gab ein potentielles Problem, wenn nämlich die Methode(n), die im run()-Loop ausgeführt werden länger dauern als die Zeit zwischen zwei Clicks hat man plötzlich 2 Threads mit run()-Loop.
Zudem wurde das ganze wiederverwendbarer.

AHF
2003-12-21, 23:27:31
danke vielmals. ich werde es in einer ruhigen minute mal implementieren.

AHF
2003-12-29, 17:57:41
was auch immer hier stand hat sich jetzt erledigt. :)