Skip to content

Commit d4fdc79

Browse files
Damon NguyenAlexander Zvegintsev
andcommitted
8344981: [REDO] JDK-6672644 JComboBox still scrolling if switch to another window and return back
Co-authored-by: Alexander Zvegintsev <[email protected]> Reviewed-by: azvegint, psadhukhan, honkar
1 parent b78043f commit d4fdc79

File tree

2 files changed

+162
-4
lines changed

2 files changed

+162
-4
lines changed

src/java.desktop/share/classes/javax/swing/plaf/basic/BasicScrollBarUI.java

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 1997, 2024, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 1997, 2025, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* This code is free software; you can redistribute it and/or modify it
@@ -1609,16 +1609,19 @@ public ScrollListener(int dir, boolean block) {
16091609

16101610
/** {@inheritDoc} */
16111611
public void actionPerformed(ActionEvent e) {
1612+
// If scrollbar isn't visible, stop the timer
1613+
if (!scrollbar.isShowing()) {
1614+
stopScrollTimer(e);
1615+
return;
1616+
}
16121617
// If frame is disabled and timer is started in mousePressed
16131618
// and mouseReleased is not called, then timer will not be stopped
16141619
// Stop the timer if frame is disabled
16151620
Component parent = scrollbar.getParent();
16161621
do {
16171622
if (parent instanceof JFrame par) {
16181623
if (!par.isEnabled()) {
1619-
((Timer)e.getSource()).stop();
1620-
buttonListener.handledEvent = false;
1621-
scrollbar.setValueIsAdjusting(false);
1624+
stopScrollTimer(e);
16221625
return;
16231626
}
16241627
break;
@@ -1660,6 +1663,12 @@ else if(direction < 0
16601663
}
16611664
}
16621665

1666+
private void stopScrollTimer(ActionEvent e) {
1667+
((Timer) e.getSource()).stop();
1668+
buttonListener.handledEvent = false;
1669+
scrollbar.setValueIsAdjusting(false);
1670+
}
1671+
16631672
private boolean isMouseLeftOfThumb() {
16641673
return trackListener.currentMouseX < getThumbBounds().x;
16651674
}
Lines changed: 149 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,149 @@
1+
/*
2+
* Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved.
3+
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4+
*
5+
* This code is free software; you can redistribute it and/or modify it
6+
* under the terms of the GNU General Public License version 2 only, as
7+
* published by the Free Software Foundation.
8+
*
9+
* This code is distributed in the hope that it will be useful, but WITHOUT
10+
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11+
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12+
* version 2 for more details (a copy is included in the LICENSE file that
13+
* accompanied this code).
14+
*
15+
* You should have received a copy of the GNU General Public License version
16+
* 2 along with this work; if not, write to the Free Software Foundation,
17+
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18+
*
19+
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20+
* or visit www.oracle.com if you need additional information or have any
21+
* questions.
22+
*/
23+
24+
import java.awt.Component;
25+
import java.awt.Point;
26+
import java.awt.Rectangle;
27+
import java.awt.Robot;
28+
import java.awt.event.InputEvent;
29+
import java.util.concurrent.FutureTask;
30+
import java.util.concurrent.TimeUnit;
31+
32+
import javax.swing.JComboBox;
33+
import javax.swing.JFrame;
34+
import javax.swing.JScrollBar;
35+
import javax.swing.JScrollPane;
36+
import javax.swing.SwingUtilities;
37+
import javax.swing.plaf.basic.BasicComboPopup;
38+
39+
/*
40+
* @test
41+
* @key headful
42+
* @bug 6672644
43+
* @summary Tests JComboBox scrollbar behavior when alt-tabbing
44+
* @run main JComboBoxScrollFocusTest
45+
*/
46+
47+
public class JComboBoxScrollFocusTest {
48+
private static Robot robot;
49+
private static JFrame comboboxFrame;
50+
private static JComboBox<String> combobox;
51+
52+
public static void main(String[] args) throws Exception {
53+
robot = new Robot();
54+
try {
55+
SwingUtilities.invokeAndWait(JComboBoxScrollFocusTest::createAndShowGUI);
56+
doTest();
57+
} finally {
58+
SwingUtilities.invokeAndWait(comboboxFrame::dispose);
59+
}
60+
}
61+
62+
private static void createAndShowGUI() {
63+
comboboxFrame = new JFrame("JComboBoxScrollFocusTest Test Frame");
64+
combobox = new JComboBox<>();
65+
for (int i = 0; i < 100; i++) {
66+
combobox.addItem(String.valueOf(i));
67+
}
68+
comboboxFrame.add(combobox);
69+
comboboxFrame.setSize(400, 200);
70+
comboboxFrame.setLocationRelativeTo(null);
71+
comboboxFrame.setVisible(true);
72+
}
73+
74+
static Rectangle getOnScreenBoundsOnEDT(Component component) throws Exception {
75+
robot.waitForIdle();
76+
FutureTask<Rectangle> task = new FutureTask<>(()
77+
-> new Rectangle(component.getLocationOnScreen(),
78+
component.getSize()));
79+
SwingUtilities.invokeLater(task);
80+
return task.get(500, TimeUnit.MILLISECONDS);
81+
}
82+
83+
private static JScrollBar getScrollBar() {
84+
BasicComboPopup popup = (BasicComboPopup) combobox
85+
.getAccessibleContext().getAccessibleChild(0);
86+
JScrollPane scrollPane = (JScrollPane) popup
87+
.getAccessibleContext().getAccessibleChild(0);
88+
return scrollPane.getVerticalScrollBar();
89+
}
90+
91+
private static int getScrollbarValue() throws Exception {
92+
FutureTask<Integer> task = new FutureTask<>(() -> {
93+
JScrollBar scrollBar = getScrollBar();
94+
return scrollBar.getValue();
95+
});
96+
SwingUtilities.invokeAndWait(task);
97+
98+
return task.get(500, TimeUnit.MILLISECONDS);
99+
}
100+
101+
private static void doTest() throws Exception {
102+
robot.waitForIdle();
103+
robot.delay(500);
104+
105+
Rectangle rectangle = getOnScreenBoundsOnEDT(combobox);
106+
107+
Point ptOpenComboboxPopup = new Point(rectangle.x + rectangle.width - 5,
108+
rectangle.y + rectangle.height / 2);
109+
110+
robot.mouseMove(ptOpenComboboxPopup.x, ptOpenComboboxPopup.y);
111+
robot.mousePress(InputEvent.BUTTON1_DOWN_MASK);
112+
robot.mouseRelease(InputEvent.BUTTON1_DOWN_MASK);
113+
robot.waitForIdle();
114+
robot.delay(500);
115+
116+
JScrollBar scrollBar = getScrollBar();
117+
118+
// Start scrolling
119+
Rectangle scrollbarBounds = getOnScreenBoundsOnEDT(scrollBar);
120+
robot.mouseMove(scrollbarBounds.x + scrollbarBounds.width / 2,
121+
scrollbarBounds.y + scrollbarBounds.height - 5);
122+
robot.mousePress(InputEvent.BUTTON1_DOWN_MASK);
123+
124+
robot.delay(1000);
125+
126+
if (getScrollbarValue() == 0) {
127+
throw new RuntimeException("The scrollbar is not scrolling");
128+
}
129+
130+
// closing popup by moving focus to the main window
131+
comboboxFrame.requestFocus();
132+
robot.waitForIdle();
133+
robot.mouseRelease(InputEvent.BUTTON1_DOWN_MASK);
134+
135+
robot.waitForIdle();
136+
robot.delay(500);
137+
138+
// open popup again
139+
robot.mouseMove(ptOpenComboboxPopup.x, ptOpenComboboxPopup.y);
140+
robot.mousePress(InputEvent.BUTTON1_DOWN_MASK);
141+
robot.mouseRelease(InputEvent.BUTTON1_DOWN_MASK);
142+
robot.waitForIdle();
143+
robot.delay(500);
144+
145+
if (getScrollbarValue() != 0) {
146+
throw new RuntimeException("The scroll bar is scrolling");
147+
}
148+
}
149+
}

0 commit comments

Comments
 (0)