> Java > tutorials > javanotes > UI-Forum
> Java > tutorials > javanotes > UI-Forum
by ZweiBieren User Interface Tricks Java coffee cup logo
Source Explorer
Java Notes

* This button downloads an installer jar. To install the app, put the jar in a folder and double-click it. Double click the application's icon to run it.

how to set mousewheel and arrow button scroll speed equal

I've experienced that when I set

scrollPane.getVerticalScrollBar().setUnitIncrement(50);
I can change the scroll speed of a JScrollPane, but there's always a difference between scrolling with the mousewheel and scrolling with the arrow buttons of the scrollbar. With the arrow buttons I always get 1/3 of the mousewheel scroll speed.
Is there a way to set them equal?

By "change the scroll speed," the user meant the number of lines of text that scrolled for a click on a scroll arrow or a twist of the mouse's scroll wheel. After some back-and-forth, I replied.

It will interfere with user expectations if you tinker with the amount of wheel scrolling. That said, here's a version of ScrollPane that has a method, setUnitsToScroll(int), that sets the number of "units" that the mouse wheel moves. Typically, a unit is one line of text.

Lousy Java code omitted here

But this won't adjust the scroll speed of the arrow buttons, will it? I want to speed them both up, but have them at the same speed

Give someone the moon and they want the sun ;-)
This is it for me this year.
Cheers until twenty-ten.

Not-as-lousy Java code omitted here

In adapting this note, I completely rewrote the scrolling code and demo. It is now ZBScrollPane.java. In the process, I learned a lot; most of which I hadn't really wanted to know ;-( 

Let's begin with the "unit increment". The idea is based on scrolling text, where the arrows at the end of a scrollbar cause scrolling by one line. The "unit" is a line of text. When the mouse wheel was introduced, operating systems decided to equate a mouse click with multiple lines. The multiplier, m, is set as an operating system parameter. (On Windows this number is on the "Mouse Wheel" tab of the "Mouse Properties" page of the control panel.) Thus when a wheek click arrives, the scroll code has to multiply the unit increment by m times the number of clicks (usually 1). If you want your app to scroll by some other distance your best hope is to set m to 1 and temporarily set the size of a unit to be whatever the whole scroll should be. This approach is followed in the processMouseWheelEvent in ZBScrollPane.

Other notes:

  • If you are scrolling something other than text, you must make the scrolled JComponent "focusable" so the page-up and page-down keys work.  In the demo I do this in a ChangeListener added to the viewport:
    Component scrollee = vp.getView();
    if (scrollee != null)
        scrollee.setFocusable(true);
  • Every programmer who touched scrolling added his or her version of how to set set the unitIncrement. Methods for this exist in (at least) JScrollPane, JScrollBar, BasicScrollPaneUI, JTextArea, JTextComponent, and Scrollable. An argument can be made for the existence of each, but the totality is hard to understand. The whole mess can be evaded by setting the scroll unit increment in a JScrollPane's getVerticalScrollBar. This ScrollBar is a subclass of ScrollBar that always uses whatever unit increment is set in it; it overrides values set in Scrollable or any other place. Accordingly ZBScrollPane alternates
    getVerticalScrollBar().setUnitIncrement(wheelUnitsIncr)
    getVerticalScrollBar().setUnitIncrement(arrowUnitsIncr)
    as needed.
  • My earlier code relied upon intercepting the notification to mouse wheel listeners. It had a separate copy of the listeners list, with the attendant risk of losing a listener. Instead the newer code intercepts the handling to the MouseWheelEvent. First the constructor asks to get mouse wheel events:
    enableEvents(AWTEvent.MOUSE_WHEEL_EVENT_MASK);
    And then an override of processMouseWheelEvent modifies the MouseWheelEvent, replacing m with replaceSystemUnitsPerClick which it has set to 1.
Give someone the moon and they want the sun ;-)

It's winter! Who doesn't want the sun? :D

Thanks a lot, will have a look at it when I solved my current problem.


changing the border of a JComboBox
I'm not talking about the normal border of the combo box but about the border of the selection menu. When I click at the JComboBox, a JList pops up like a drop down selection menu. But it is always surrounded by a thin black line border. Is it possible to change the color of the border? Or even remove it?
Changing any setting of the JList or the JComboBox didn't do anything concerning that issue, didn't find any setting in the cell renderer either. I don't even know where that border comes from ... I know it's not coming from the JList, when I add one to my panel it has no border, I know though that the combo box overrides some color settings of the list so I guess it's something originating from the combo box doing some secret setting that is not to be found by anyone ... or does anybody know?

To change the user interface, you have to change the UI. (Yeah sure, but how?)

I adapted an earlier JComboBox demo to show how. It is attached. ComboBoxRenderer.java

Only two steps were needed.

Step 1. Define class MyComboBoxUI:

// to set border of popup
static class MyComboBoxUI extends WindowsComboBoxUI {
    protected ComboPopup createPopup() {
        BasicComboPopup bcp 
            = (BasicComboPopup) super.createPopup();

        // set the border around the popup
        bcp.setBorder(BorderFactory
            .createLineBorder(Color.red, 3));

        // there is an inner border around the list, 
        // inside the scroller; it can be set thus:
        //     JList list = bcp.getList();
        //     list.setBorder(BorderFactory
        //             .createLineBorder(Color.green, 2));

        return bcp;
    }
}

The pop-up menu
has a red border.
Step 2. Use MyComboBoxUI. Add one line after constructing the JComboBox. The result is to the right.
// Create the combo box.
JComboBox colorList = new JComboBox();
colorList.setUI(new MyComboBoxUI()); 

There is a big problem: We are overriding the ComboBox for the Windows look-and-feel. And we are installing that look-and-feel for this combobox no matter what platform the application is running on. The point of look-and-feel is to have an interface that is consistent across all applications. Changing the popup border means that your application is different. This is not a good thing for the user.

As far as I can see, there is no way to change the popup border so that it changes for all look-and-feels.


JEditorPane, HTML 4.0, CSS, custom Tags

I recently discovered the HTML Feature of JTextPane and JEditorPane. This features comes in handy for one problem I have. I have to highlight some areas/words in a text and I thought of HTML.

But there is a problem: as we all want to use standards I wanted to use css for styling. And I thought about a custom tag in the text. And there is a problem:

The code below does not render the text properly. However, the browser (Firefox) renders the content right. and of course i can use the <font> tag instead, but this is deprecated. How to solve this problem?

Thanks in advance,
Andre

private static String webContent = "<html>" +
    "<head>" +
    "<style type=\"text/css\">mytag {color:red}</style>" +
    "</head>" +
    "<body>" +
    "<p>Hello <mytag>World</mytag></p>" +
    "</body>" +
    "</html>";

public static void main(String[] args) {
    JFrame f = new JFrame("HTML Example");

    JEditorPane jep = new JEditorPane();    
    jep.setEditorKit(new HTMLEditorKit());
    jep.setText(webContent);

    f.add(jep);

    f.pack();
    f.setSize(300, 200);
    f.setDefaultCloseOperation(
        WindowConstants.DISPOSE_ON_CLOSE);
    f.setVisible(true);
}

JEditStyles.java

Stylesheets are supported in JTextComponents via HTMLEditorKit. Newly invented tags don't work, at least not out of the box.
And styles don't work in Labels and buttons.

JEditStyles opens a window with a JEditorPane on the right and its result shown in a JLabel on the left:
Window showing edited styles


Can't close JFrame
I need a way to close my JFrame from my Mouse Adapter. System.exit(0); doesn't work in any method.

import java.awt.*;
import javax.swing.*;
import javax.imageio.*;
import java.awt.Graphics.*;
import java.io.*;
import java.awt.image.*;
import java.awt.Component.*;
import java.*;
import javax.*;
import java.awt.event.*;
public class StatxMenu extends JPanel{
    BufferedImage Back = ImageIO.read(new File ("StatMenu.png"));
    BufferedImage Skills = ImageIO.read(new File ("Skills.png"));
    BufferedImage System = ImageIO.read(new File ("System.png"));
    Dimension dim = new Dimension(Back.getWidth(), Back.getHeight());
    boolean bSkills = false, bSystem = false;
    public StatxMenu() throws IOException{
        setPreferredSize(dim);
        setFocusable(true);
        addMouseListener(new MouseAdapter() {
            public void mouseReleased(MouseEvent me) {
                if (me.getX()>390 && me.getY()<10){
                }
                repaint();
            }
        });
    }
    public void paint(Graphics g){
        g.drawImage(Back, 0, 0, this);
        g.drawImage(Skills, 20, 20, this);
        g.drawImage(System, 20, 515, this);
    }
    public static void main(String args[])throws IOException{
        JFrame frame = new JFrame();
        frame.getContentPane().add(new StatxMenu());
        frame.pack();
        frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
        frame.setLocationRelativeTo(null);
        frame.setVisible(true);
    }
}
Thanks

My most recent application distinguishes between

  • close the window
  • exit the application
In principle, the application could launch multiple copies of the main window. So the application would exit only after all windows are closed. Each of the following code segments incorporates a wrinkle I had to ferret out to implement this approach.

The window code is ready for a user click on the X icon on the title bar to close the window. In this case, the window is Disposed,
and a "SHUTDOWN" event is sent (through a "comm" object).
setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
addWindowListener(new WindowAdapter() {
    @Override
    public void windowClosing(WindowEvent we) {
        comm.say(TaggerComm.ID.SHUTDOWN, null, "window close");
    }
});

There is also a CLOSE button within the main window. When the user clicks it, this code simulates a click on the X button. In consequence, this code will result in a call on the code just above.
getToolkit().getSystemEventQueue()
        .postEvent(new WindowEvent(TaggerFrame.this,
                WindowEvent.WINDOW_CLOSING));

The main application waits for SHUTDOWN events. After all windows are closed, the application exits thusly:
// arrange to exit after all listeners process the SHUTDOWN
java.awt.EventQueue.invokeLater(
    new Runnable() { public void run() { System.exit(0); }}  );
 
Copyright © 2023 ZweiBieren, All rights reserved. Feb 1, 2023 21:35 GMT Page maintained by ZweiBieren