How to make JPanels respond to MouseDragged? - java

So, I've been working on a program that lets you click/drag over a grid of JPanels, and changes the background colors of the JPanels that you have clicked on or dragged over (you can set the colors using JRadioButtons). I've gotten the point where if I click on a JPanel, it responds and changes colors. However, if I simply do:
public void mouseClicked(MouseEvent e){
((JPanel)e.getSource()).setBackground(color_chosen);
}
public void mouseDragged(MouseEvent e){
System.out.println("Calling mouseClicked"); // debugging
mouseClicked(e);
}
the program only responds to mouse clicks, and doesn't recolor the backgrounds of the JPanels affected by the mouse drag. In addition, its puzzling to me that "Calling mouseClicked" still prints out, but no background colors change.
I'd appreciate some help trying to figure out where I went wrong, so that any panel that I drag over changes its background color to a pre-specified chosen color.
Thanks.

Related

Unexpected behaviour with JButtons and JPanels

I've started adding a few buttons to my new Java Swing project (first time using Swing) and I tried adding a mouse listener event to them with the intention of having the background of the (transparent) button to change to a darker color when the mouse is hovering over it.
I did this using JPanels behind the the buttons, and I tried changing their backgrounds to a 50% opaque color.
Code:
for(int i=0;i<5;i++){
JPanel p = new JPanel();
p.setOpaque(false);
b[i].setContentAreaFilled(false); //b is an array consisting of 5 buttons
b[i].setForeground(Color.RED); //
b[i].addMouseListener(new MouseAdapter() {
public void mouseEntered(MouseEvent e) {
p.setOpaque(true);
p.setBackground(new Color(0,0,0,50));
}
public void mouseExited(MouseEvent e){
p.setOpaque(false);
p.setBackground(new Color(0,0,0,0));
}
p.add(b[i]);
}
I have multiple unexpected things happen with this code:
Every time I click the button (I have no ActionListener on them) the button (and only the button, not the panel behind it) gets increasingly darker until it reaches black.
If I hover over a (white) button in another part of the program first, then over any of these buttons the panels behind them become white instead of a darker version of the original color.
If I hover over any of these buttons, and then over another one of them afterwards, the second button seems to display the text of BOTH of the buttons.
Screenshots:
1: https://cdn.discordapp.com/attachments/871490774301294642/957684879712219168/unknown.png
2: https://cdn.discordapp.com/attachments/871490774301294642/957685306562338826/unknown.png
3: https://cdn.discordapp.com/attachments/871490774301294642/957685596900438086/unknown.png
Maybe I'm doing something blatantly wrong but I'm quite new to Swing so sorry if that is the case. Any help appreciated.

Can you make the background of a JScrollBar transparent?

I have a series of column labels that scrolls independently from the data that is displayed in a matrix below. I can make the whole scrollbar transparent except on hover. The labels are right up against the data, which I like, however, upon hover, unless I shift the vertical scroll (which I'd rather not do), the scrollbar obscures the beginning of all the labels.
I would like to set the background of the scrollbar as transparent so that only the "grabber" (or whatever it's called) is the only thing that is drawn. (It will obscure the beginning of the labels it is over, but would be a lot less so.)
Is there any way to do that? Here is what I tried:
Color bg = new Color(255,255,255,0);
colLabelScroll.setBackground(bg);
This does not seem to make the background of the scrollbar transparent.
What I'm shooting for is like how the iPhone's scrollbar grabber hovers over info in some apps. Is that even possible with JScrollBars?
Transparent JScrollBar can do it, but consider this: if column labels are related to the data and you can scroll them independently, beginner users may not understand what is going on and associate column labels with whatever is visually aligned beneath it. Either you will need some sort of visual indicator that makes it clear that the labels are disconnected from the data, or you should change the way labels are scrolled that never leaves them statically in 1 place.
Here's how I ended up making the relationship between the labels and the data clearer:
Instead of allowing the user to independently and intentionally scroll the labels, I decided to control the label scroll position via mouse hover. This eliminates the need for the obtrusive scrollbar.
I created a scroll-bar-like indicator that shows the portion of the data the labels represent.
I highlighted the currently hovered label that corresponds to the data below it, i.e. the only label that is ever correctly aligned with the data is the one that is under (or directly above) the cursor.
When the mouse is not hovered over (or dragging from) the column labels, do not display any labels. This helps prevent invalid label/data associations by the user.
A few nuanced notes: Implementing your own scrollbar-like indicator is somewhat involved, especially if your labels are painted and then rotated, because the paint position of 0 is at the bottom of the pane, yet the vertical scroll position of the pane is at the top. You will have to track the vertical scroll position to be able to recover it again when the cursor returns since you are blanking the labels on mouse out.
When developing a plugin for IntelliJ, I accomplished it with:
scrollPane.getVerticalScrollBar().setUI(ButtonlessScrollBarUI.createTransparent());
It takes advantage of the the:
ButtonlessScrollBarUI.createTransparent()
method, which is an IntelliJ specific method. However, if you can find a ScrollBarUI which has a transparent background, you can use the same trick.
Since I got a bit lost myself at first after reading #hepcat72's answer I'm posting a little explanation about the BasicScrollBarUI class:
JScrollBar scrollbar = scrollPaneConversation.getVerticalScrollBar();
scrollbar.setUI(new BasicScrollBarUI(){
// This function returns a JButton to be used as the increase button
// You could create your own customized button or return an empty(invisible) button
#Override
protected JButton createIncreaseButton(int orientation){
}
// Same as above for decrease button
#Override
protected JButton createDecreaseButton(int orientation){
}
// This function paints the "track" a.k.a the background of the scrollbar
// If you want no background just return from this function without doing anything
// If you want a custom background you can paint the 'Graphics g' object as you like
#Override
protected void paintTrack(Graphics g, JComponent c, Rectangle trackBounds)
{
}
// This function paints the "thumb" a.k.a the thingy that you drag up and down
// You can override this function to paint it as you like
#Override
protected void paintThumb(Graphics g, JComponent c, Rectangle thumbBounds)
{
}
});
Refer to the Transparent JScrollBar link posted by #hepcat72 for hints about what to do exactly in these functions.

Resize code does not correspond with mouse movement

I have some code to resize a chatpanel dynamically, but it does not move according to the mouse. What happens is the mouse moves at a faster rate than the panel gets resized. For example, how I want it to be, is in any application, when you click on the border between two windows, and drag it, the mouse stays along with the piece you are clicking on, and currently this is not happening. here is my code. please let me know if you need more
public void mouseDragged(MouseEvent e) {
if(getCursor().getType() == Cursor.getPredefinedCursor(Cursor.N_RESIZE_CURSOR).getType()) {
owner.adjust((int)MouseInfo.getPointerInfo().getLocation().getY());
System.out.println("vertpanel: "+(int)MouseInfo.getPointerInfo().getLocation().getY());
}
}
public void adjust(int adjustment) {
int height = this.getHeight();
System.out.println((((double)(adjustment))/height)+":"+(((double)(height-adjustment))/height));
output.setHeightPercent((((double)(adjustment))/height));
output.componentResized(new ComponentEvent(this, 1));
input.setHeightPercent((((double)(height-adjustment))/height));
input.componentResized(new ComponentEvent(this, 2));
}
there is one main panel, a chatpanel, and within it, there are two smaller panels, a chat input and a chat output
Can't tell exactly what you are doing based on your code.
I would suggest that you should NOT be manually setting the dimensions of the output and input coponents. You should let the layout manager determine how to resize each component as the parent container is resized.
So in your resize code you would need to invoke revalidate() on the parent container as it is resized.
Check out Resizing Components. You should be able to use the ComponentResizer class as long as you use setAutoLayout(true).

How to repaint on resize of a custom JSlider

Easy Java question here. I have made a custom JSlider which paints squares at the last location the user has moved the slider to. We override paintcomponent and draw the squares relative to the size of the slider. Everything works good when you use the slider properly. Problems happen though when you resize the frame. The slider grows bigger, and the slider adjuster moves with it, but our squares that we placed don't move relative to the slider. Which function should we use from JSlider to repaint when we resize the frame?
I am trying to keep the JSlider code separate from the frame code, so we want the user to be able to use our custom JSlider and not be trying to handle this resizing feature themselves. Any help on which method we should use for this?
Thanks.
You can add a ComponentListener to your slider that repaints it on componentResized.
slider.addComponentListener(new ComponentAdapter() {
#Override
public void componentResized(ComponentEvent e) {
e.getComponent().repaint();
}
}

How to prevent Mouse Listener temporally on window?

I'm writing a game in Java and this is the first one that I'm trying to make "pretty". The game is called Bantumi - it's a board game and right now I'm programming the animations for the movements. The problem is that, when the movement animation is running, the board still gets the Mouse Event and if the user selects a new movement, the running one will be discarded.
For the board I'm using a class extending JLayeredPane. This how I have my layers:
Layer 0: The Holes with the seeds, so the users selects one for the movement, each Hole being a JPanel with a MouseListener.
Layer 1: The Highlight that marks the currently selected Hole
Layer 2: The Animation of the Movement.
Layer 10: A custom notification system class that I wrote, it says things like "Your Turn", "Repeat Turn", "You win", etc.
I want to prevent every possible mouse event in any of this layers while the animation is running, how do I do that? I thought that adding a panel covering the whole area in a top player was enough but it didn't work. Any workaround?
For (temporarily) disabling events from MouseListener (KeyListener ....) you can use
public void consume()
Consumes this event so that it will not be processed in the
default manner by the source which originated it.
for example
whatever.addMouseListener(new MouseListener() {
public void mouseClicked(MouseEvent e) {
if (somethingIsTrue) {
//do some stuff from mouse listener
} else {
e.consume();
}
}
.
.
.
}
I thought that adding a panel covering the whole area in a top player was enough but it didn't work.
If this is a Swing GUI, you've already got a JPanel that covers the top level window, the glassPane, but the only way to make this work is you have to add a MouseListener (or both MouseListener and MouseMotionListener), and you have to make it visible.
You can get the top window's glasspane by calling getGlassPane() on either a top level window or its root pane, add a MouseListener and MouseMotionListener to it, and then whenever you want to make the GUI unresponsive to mouse events, set the glass pane to visible by calling setVisble(true) on it. You can toggle this effect off by doing the converse, by calling setVisble(false).

Categories

Resources