JTree aktualisieren nach Mausklick

mariusmeier

Mitglied
Hallo zusammen

Ich habe mir einen eigenen TableCellRenderer erstellt. Wie kann ich nun erreichen, dass bei einem doppelklick auf eine entsprechende Node dieser CellRenderer nochmals ausgeführt wird? Das möchte ich darum erreichen, weil der Renderer das NodeObject auf seinen Status überprüfen soll. Je nach Status der internen Variabel des Node Objects soll ein anderes Icon gezeichnet werden.

MFG
 
Da gibt's mehrere Möglichkeiten, die u.a. von Deiner Implementierung abhängen.
Du kannst es Dir einfach machen und tree.repaint() aufrufen.
Wenn Du ein DefaultTreeModel verwendest kannst Du auch an diesem
Code:
nodeChanged(TreeNode node)
aufrufen, das sollte ebenfalls ein Neuzeichnen des Knotens bewirken.
 
Das funktioniert beides nicht. Erst wenn ich den Focus vom JTree auf ein anderes Panel richte, dann wird der TreeCellRenderer aufgerufen. Was könnte das Problem sein?

Java:
if(defaultMutable.getNodeObject() instanceof Channel) {
treeModel.nodeChanged(defaultMutable);

}

MFG
 
Sorry, bei mir funktionieren beide Varianten ;-)

Vielleicht liegt es ja daran, wie Du die Objekte veränderst. Kannst Du kurzgefassten und kompilierbaren Bsp Code posten?
 
Überprüf erstmal ob du auf dem EventDispatchThread bist:
Java:
boolean eventDispatchThread = SwingUtilities.isEventDispatchThread();
System.out.println("eventDispatchThread = " + eventDispatchThread);
Mit SwingUtilities.invokeLater(..) kannst du bei Bedarf deinen Code auf den EventDispatchThread schicken.

Generell funtioniert das so: wenn der Status von einem NodeObject ändert, schick das TreeModel einfach einen treeNodesChanged(TreeModelEvent e) an alle TreeModelListener. Fertig. Der JTree kümmert sich dann um die korrekte Anzeige gemäß dem eingestellten TreeCellRenderer (ich gehe mal davon aus, dass dein "TableCellRenderer" eigentlich ein TreeCellRenderer ist).

DefaultTreeModel#nodeChanged (der Vorschlag von Michael...) macht im Wesentlich auch nichts anderes als treeNodesChanged(TreeModelEvent e) für alle TreeModelListener aufzurufen.

Es ist aber wichtig, dass dies auf dem EventDispatchThread geschieht.
 
Zuletzt bearbeitet:
Ok folgenden Code habe ich:

JTree:

Java:
public class PanelFrontendTree extends JPanel implements Observer, ActionListener {
	private JTree frontendTree;
	private JScrollPane scFrontendTree;
	private FrontendMutableTreeNode mutableRootTree;
	private DefaultTreeModel treeModel;
	//Toolbar Components
	private JToolBar treeBar;
	private JButtonLocale newFrontend;
	private JButtonLocale deleteFrontend;
	private JProgressBar pbStatus;
	private TreeController treeController;
	private TreeCellRenderer renderer;
	private Controller controller;
	
	public PanelFrontendTree(JTabbedPane pane) {
		mutableRootTree = new FrontendMutableTreeNode("Device Browser", null);
		treeModel = new DefaultTreeModel(mutableRootTree);
		frontendTree = new JTree(treeModel);
		renderer = new SpecificTreeCellRenderer();
		frontendTree.setCellRenderer(renderer);
		ToolTipManager.sharedInstance().registerComponent(frontendTree);
		treeController = new TreeController(treeModel, mutableRootTree, frontendTree, pane);
		
		frontendTree.addMouseListener(new MouseAdapter() {
			@Override
			public void mouseClicked(MouseEvent evt) {
				if(evt.getClickCount() >= 2) {
					JTree tree = (JTree)evt.getSource();
					DefaultTreeModel model = (DefaultTreeModel) tree.getModel();
					TreePath tp = tree.getClosestPathForLocation(evt.getX(), evt.getY());
					FrontendMutableTreeNode defaultMutable = (FrontendMutableTreeNode)tp.getLastPathComponent();
					//Get user specified Node Object (Frontend, Device, Channel)
					if(defaultMutable.getNodeObject() instanceof Frontend) {
						Frontend frontend = (Frontend)defaultMutable.getNodeObject();
						if(frontend != null) {
							System.out.println("FrontendName: " + frontend.getFrontendName());
							System.out.println("FrontendIP: " + frontend.getFrontendIP());
						}
					}
					
					if(defaultMutable.getNodeObject() instanceof Channel) {
						Channel channel = (Channel)defaultMutable.getNodeObject();
						
						String activeMeasureChannels = "";
						Frontend frontend = channel.getDevice().getFrontend();
						Device device = frontend.getDevice(channel.getDevice().getDeviceType());						
						activeMeasureChannels = device.getActiveMeasureChannels(channel.getChannelName());
						
						if(!channel.isActive()) {
							boolean eventDispatchThread = SwingUtilities.isEventDispatchThread();
							System.out.println("eventDispatchThread = " + eventDispatchThread);
							
							DefaultTreeModel model2 = ((DefaultTreeModel) tree.getModel());
						/*Hier sollte Node aktualisiert werden*/	==> model2.nodeChanged(defaultMutable);
							
							
							
							//Set the continous mode for the specific frontend (Connection will be refreshed automatically every 5 seconds / see ComController)
							ICom comC = ComController.getInstance();
							comC.setContinousConnection(true, frontend.getFrontendAddress(), frontend.getDeviceConnectionType());
							//Request that channel should be active
							XMLWriter xmlWriter = XMLWriter.getInstance();
							xmlWriter.setActiveMeasureChannel(channel, activeMeasureChannels, channel.getStreams(), true);
						}

TreeCellRenderer:

Java:
public class SpecificTreeCellRenderer implements TreeCellRenderer {
	
	ImageIcon deviceIcon;
	ImageIcon deviceActiveIcon;
	ImageIcon deviceInactiveIcon;
	ImageIcon deviceTypeEth;
	ImageIcon deviceTypeUsb;
	
	DefaultTreeCellRenderer defaultRenderer = new DefaultTreeCellRenderer();
	
	public SpecificTreeCellRenderer() {
		deviceTypeEth = new ImageIcon(getClass().getResource("/images/networkWired.png"));
		deviceTypeUsb = new ImageIcon(getClass().getResource("/images/usbWired.png"));
		deviceIcon = new ImageIcon(getClass().getResource("/images/device.png"));
		deviceActiveIcon = new ImageIcon(getClass().getResource("/images/active.png"));
		deviceInactiveIcon = new ImageIcon(getClass().getResource("/images/inactive.png"));
		
	}

	@Override
	public Component getTreeCellRendererComponent(JTree tree, Object obj, boolean selected, boolean expanded, boolean leaf, int row, boolean hasFocus) {
		Component returnValue = null;

		if((obj != null) && (obj instanceof FrontendMutableTreeNode)) {
			Object userObject = ((FrontendMutableTreeNode) obj).getNodeObject();
			FrontendMutableTreeNode treeNode = (FrontendMutableTreeNode) obj;
			
			if (userObject instanceof Frontend) {
				Frontend frontend = (Frontend) userObject;
				if(frontend.getDeviceConnectionType().equals(ComGlobal.deviceDriverETHTcp)) {
					JPanel panelFrontend = createComponent(deviceIcon, frontend.getFrontendName(), deviceTypeEth, tree.getBackground(), selected);
					panelFrontend.setToolTipText("Frontend => Type: " + frontend.getDeviceConnectionType() + "  Address: " + frontend.getFrontendAddress());
					returnValue = panelFrontend;
				} else if(frontend.getDeviceConnectionType().equals(ComGlobal.deviceDriverUSB)) {
					JPanel panelFrontend = createComponent(deviceIcon, frontend.getFrontendName(), deviceTypeUsb, tree.getBackground(), selected);
					panelFrontend.setToolTipText("Frontend => Type: " + frontend.getDeviceConnectionType() + "  Address: " + frontend.getFrontendAddress());
					returnValue = panelFrontend;
				}
			} else if (userObject instanceof Device) {
				Device device = (Device) userObject;
				
				returnValue = createComponent(deviceIcon, device.getDeviceType(), null, tree.getBackground(), selected);
			} else if (userObject instanceof Channel) {
				Channel channel = (Channel) userObject;
				if(channel.isActive()) {
					System.err.println("CHANNEL ACTIVE!");
					JPanel panelChannel = createComponent(deviceIcon, channel.getChannelName(), deviceActiveIcon, tree.getBackground(), selected);
					panelChannel.setToolTipText("Channel is active");
					returnValue = panelChannel;
				} else {
					JPanel panelChannel = createComponent(deviceIcon, channel.getChannelName(), deviceInactiveIcon, tree.getBackground(), selected);
					panelChannel.setToolTipText("Channel is offline");
					returnValue = panelChannel;
				}
			}
		}
		
		if (returnValue == null) {
		      returnValue = defaultRenderer.getTreeCellRendererComponent(tree,
		          obj, selected, expanded, leaf, row, hasFocus);
		}
		
		return returnValue;
	}
	
	public JPanel createComponent(ImageIcon icon, String device, ImageIcon statusIcon, Color backgroundColor, boolean selected) {
		JPanel panelFrontend = new JPanel();
		
		JLabel lbName = new JLabel(device);
		JLabel lbDeviceIcon = new JLabel(deviceIcon);
		JLabel lbStatusOfDeviceIcon = new JLabel(statusIcon);
		
		lbName.setPreferredSize(new Dimension(60,22));
		lbName.setMinimumSize(new Dimension(60,22));
		lbName.setToolTipText("Test");
		lbDeviceIcon.setPreferredSize(new Dimension(22,22));
		lbDeviceIcon.setMinimumSize(new Dimension(22,22));
		lbStatusOfDeviceIcon.setPreferredSize(new Dimension(22,22));
		lbStatusOfDeviceIcon.setMinimumSize(new Dimension(22,22));
		
		lbName.setOpaque(true);
		lbDeviceIcon.setOpaque(true);
		lbStatusOfDeviceIcon.setOpaque(true);
		lbName.setBackground(backgroundColor);
		lbDeviceIcon.setBackground(backgroundColor);
		lbStatusOfDeviceIcon.setBackground(backgroundColor);
		panelFrontend.setBackground(backgroundColor);
		
		if(selected) {
			panelFrontend.setBorder(BorderFactory.createLineBorder(Color.LIGHT_GRAY.brighter().brighter()));
		}
		
		panelFrontend.setLayout(new GridBagLayout());
		panelFrontend.add(lbDeviceIcon, new GridBagConstraints(0, 0, 1, 1, 1.0, 1.0, GridBagConstraints.CENTER, GridBagConstraints.BOTH, new Insets(2, 2, 0, 2), 0, 0));
		panelFrontend.add(lbName, new GridBagConstraints(1, 0, 1, 1, 1.0, 1.0, GridBagConstraints.CENTER, GridBagConstraints.BOTH, new Insets(2, 7, 0, 10), 0, 0));
		panelFrontend.add(lbStatusOfDeviceIcon, new GridBagConstraints(2, 0, 1, 1, 1.0, 1.0, GridBagConstraints.CENTER, GridBagConstraints.BOTH, new Insets(2, 0, 0, 2), 0, 0));
		
		return panelFrontend;
	}
}

MFG
 
Werde mir den Code mal in einer ruhigen Minute anschauen.
Aber vorweg schon mal was zu der createComponent(...) im Renderer - nicht gerade schön.
Du erzeugst da jedes mal neue Komponenten inkl. Layoutdefinition, erzeugst gegebenenfalls eine neue Border. Sinn und Zweck eines Renderers ist es eine Komponente einmal zu erzeugen und sie immer wieder zu verwenden. Erzeug so ein panelFrontend nur einmal bei der Initialisierung des Renderes und über gibt diesem einfach nur die neuen Werte und setze bei Selektion eine Border, die man eigentlich auch bei der Initialisierung des Renderers einmalig erzeugen könnte. Die Icons sind ja eh immer die selben, wenn ich das richtig gesehen habe.
 
Habe das korrigiert was du gesagt hast. Ist nun einiges besser geworden beim erstellen des JTree's. Da wird wohl noch of ein fireChange() ausgeführt 😉 . Trotzdem besteht noch immer das Problem, dass beim klicken auf ein CHannel Node das Icon nicht sofort wechselt.

Java:
public class SpecificTreeCellRenderer implements TreeCellRenderer {
	
	ImageIcon deviceIcon;
	ImageIcon deviceActiveIcon;
	ImageIcon deviceInactiveIcon;
	ImageIcon deviceTypeEth;
	ImageIcon deviceTypeUsb;
	Border border;
	JPanel panelFrontend;
	JLabel lbName;
	JLabel lbDeviceIcon;
	JLabel lbStatusOfDeviceIcon;
	
	DefaultTreeCellRenderer defaultRenderer = new DefaultTreeCellRenderer();
	
	public SpecificTreeCellRenderer() {
		deviceTypeEth = new ImageIcon(getClass().getResource("/images/networkWired.png"));
		deviceTypeUsb = new ImageIcon(getClass().getResource("/images/usbWired.png"));
		deviceIcon = new ImageIcon(getClass().getResource("/images/device.png"));
		deviceActiveIcon = new ImageIcon(getClass().getResource("/images/active.png"));
		deviceInactiveIcon = new ImageIcon(getClass().getResource("/images/inactive.png"));
		
		panelFrontend = new JPanel();
		
		lbName = new JLabel();
		lbDeviceIcon = new JLabel(deviceIcon);
		lbStatusOfDeviceIcon = new JLabel();
		
		lbName.setPreferredSize(new Dimension(60,22));
		lbName.setMinimumSize(new Dimension(60,22));
		lbDeviceIcon.setPreferredSize(new Dimension(22,22));
		lbDeviceIcon.setMinimumSize(new Dimension(22,22));
		lbStatusOfDeviceIcon.setPreferredSize(new Dimension(22,22));
		lbStatusOfDeviceIcon.setMinimumSize(new Dimension(22,22));
		
		lbName.setOpaque(true);
		lbDeviceIcon.setOpaque(true);
		lbStatusOfDeviceIcon.setOpaque(true);
		/*lbName.setBackground(backgroundColor);
		lbDeviceIcon.setBackground(backgroundColor);
		lbStatusOfDeviceIcon.setBackground(backgroundColor);
		panelFrontend.setBackground(backgroundColor);*/
	
		border = BorderFactory.createLineBorder(Color.LIGHT_GRAY.brighter().brighter());
		
		panelFrontend.setLayout(new GridBagLayout());
		panelFrontend.add(lbDeviceIcon, new GridBagConstraints(0, 0, 1, 1, 1.0, 1.0, GridBagConstraints.CENTER, GridBagConstraints.BOTH, new Insets(2, 2, 0, 2), 0, 0));
		panelFrontend.add(lbName, new GridBagConstraints(1, 0, 1, 1, 1.0, 1.0, GridBagConstraints.CENTER, GridBagConstraints.BOTH, new Insets(2, 7, 0, 10), 0, 0));
		panelFrontend.add(lbStatusOfDeviceIcon, new GridBagConstraints(2, 0, 1, 1, 1.0, 1.0, GridBagConstraints.CENTER, GridBagConstraints.BOTH, new Insets(2, 0, 0, 2), 0, 0));
		
		
	}

	@Override
	public Component getTreeCellRendererComponent(JTree tree, Object obj, boolean selected, boolean expanded, boolean leaf, int row, boolean hasFocus) {
		Component returnValue = null;

		if((obj != null) && (obj instanceof FrontendMutableTreeNode)) {
			Object userObject = ((FrontendMutableTreeNode) obj).getNodeObject();
			FrontendMutableTreeNode treeNode = (FrontendMutableTreeNode) obj;
			
			lbDeviceIcon.setBackground(tree.getBackground());
			lbName.setBackground(tree.getBackground());
			lbStatusOfDeviceIcon.setBackground(tree.getBackground());
			panelFrontend.setBackground(tree.getBackground());
			
			if (userObject instanceof Frontend) {
				Frontend frontend = (Frontend) userObject;
				lbName.setText(frontend.getFrontendName());
				
				if(selected) {
					panelFrontend.setBorder(border);
				} else {
					panelFrontend.setBorder(null);
				}
				
				if(frontend.getDeviceConnectionType().equals(ComGlobal.deviceDriverETHTcp)) {
					panelFrontend.setToolTipText("Frontend => Type: " + frontend.getDeviceConnectionType() + "  Address: " + frontend.getFrontendAddress());
					lbStatusOfDeviceIcon.setIcon(deviceTypeEth);
					returnValue = panelFrontend;
				} else if(frontend.getDeviceConnectionType().equals(ComGlobal.deviceDriverUSB)) {
					panelFrontend.setToolTipText("Frontend => Type: " + frontend.getDeviceConnectionType() + "  Address: " + frontend.getFrontendAddress());
					lbStatusOfDeviceIcon.setIcon(deviceTypeUsb);
					returnValue = panelFrontend;
				}
			} else if (userObject instanceof Device) {
				if(selected) {
					panelFrontend.setBorder(border);
				} else {
					panelFrontend.setBorder(null);
				}
				Device device = (Device) userObject;
				lbStatusOfDeviceIcon.setIcon(null);
				lbName.setText(device.getDeviceType());
				returnValue = panelFrontend;
			} else if (userObject instanceof Channel) {
				if(selected) {
					panelFrontend.setBorder(border);
				} else {
					panelFrontend.setBorder(null);
				}
				Channel channel = (Channel) userObject;
				lbName.setText(channel.getChannelName());
				if(channel.isActive()) {
					System.err.println("CHANNEL ACTIVE!");
					lbStatusOfDeviceIcon.setIcon(deviceActiveIcon);
					panelFrontend.setToolTipText("Channel is active");
					returnValue = panelFrontend;
				} else {
					lbStatusOfDeviceIcon.setIcon(deviceInactiveIcon);
					panelFrontend.setToolTipText("Channel is offline");
					returnValue = panelFrontend;
				}
			}
		}
		
		if (returnValue == null) {
		      returnValue = defaultRenderer.getTreeCellRendererComponent(tree,
		          obj, selected, expanded, leaf, row, hasFocus);
		}
		
		return returnValue;
	}
}

MFG
 
MH habe mal unabhängig von meinem Projekt ein einfaches Beispiel gemacht mit demselben Renderer. Da funktioniert dass mit dem nodeChanged()! Der TimerTask stellt nach 2 sekunden die Variable des Frontend's auf true und ruft danach nodeChanged() auf.

Java:
public class TreeFrame extends JFrame{

	private JTree frontendTree;
	private JScrollPane scFrontendTree;
	private FrontendMutableTreeNode mutableRootTree;
	private DefaultTreeModel treeModel;
	//Toolbar Components
	private JToolBar treeBar;
	private JProgressBar pbStatus;
	private TreeCellRenderer renderer;
	Timer timer = null;
	
	public TreeFrame() {
		mutableRootTree = new FrontendMutableTreeNode("Device Browser", null);
		treeModel = new DefaultTreeModel(mutableRootTree);
		frontendTree = new JTree(treeModel);
		renderer = new SpecificTreeCellRenderer();
		frontendTree.setCellRenderer(renderer);
		ToolTipManager.sharedInstance().registerComponent(frontendTree);
		
		FrontendMutableTreeNode node1 = new FrontendMutableTreeNode("dev0", new Frontend());
		mutableRootTree.add(node1);
		
		setLayout(new FlowLayout());
		add(frontendTree);
		
		timer = new Timer();
		timer.schedule(new doTimer(node1, treeModel), 2000);
	}
	
	public static void main(String [] args) {
		TreeFrame frame = new TreeFrame();
		frame.setSize(new Dimension(500,500));
		frame.setVisible(true);
	}
	
	class doTimer extends TimerTask {
		FrontendMutableTreeNode node;
		DefaultTreeModel treeModel;
		
		public doTimer(FrontendMutableTreeNode node, DefaultTreeModel treeModel) {
			this.node = node;
			this.treeModel = treeModel;
		}
		
		@Override
		public void run() {
			System.err.println("Timer run!");
			Frontend frontend = (Frontend)node.getNodeObject();
			frontend.isActive = true;
			treeModel.nodeChanged(node);
		}
		
	}
	
	class Frontend {
		public boolean isActive = false;
	}
}
 
Ach man hab was ganz dummes gefunden. Jetzt gehts!! Das ganze hätte eigentlich schon längst funktioniert!!! Habe aber nur die Variable von der Klasse Channel (isActive) gar nie auf true geschaltet. Erst später wurde diese Variable auf true gesetzt. Desshalb auch die Verzögerung 🙂

MFG
 

Neue Themen


Zurück
Oben