Java JComboBox确定项目是否为';在下拉列表中不可见

Java JComboBox确定项目是否为';在下拉列表中不可见,java,swing,popup,jcombobox,viewport,Java,Swing,Popup,Jcombobox,Viewport,我试图从JComboBox下拉列表中确定每个项目在JViewPort中是否可见 (星期五加班) 编辑:我不想为向System.out.print(…)重复事件实现MouseListener 不可能用JList传递JComboBox,JCombo#Model使用SwingUtilities声明,但是这个APi不在我的范围内 import java.awt.*; import java.awt.event.*; import javax.swing.*; public class ItemVisi

我试图从JComboBox下拉列表中确定每个项目在JViewPort中是否可见

(星期五加班)

编辑:我不想为向System.out.print(…)重复事件实现MouseListener

不可能用JList传递JComboBox,JCombo#Model使用SwingUtilities声明,但是这个APi不在我的范围内

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;

public class ItemVisibleRecCombo extends JFrame {

    private static final long serialVersionUID = 1L;
    private JComboBox fontsBox;

    public ItemVisibleRecCombo() {
        String[] numbers = {"one", "two", "three", "four", "five", "six", "seven"};
        fontsBox = new JComboBox(numbers);
        fontsBox.setSelectedItem(0);
        fontsBox.addItemListener(new ItemListener() {

            @Override
            public void itemStateChanged(ItemEvent e) {
                if (e.getStateChange() == ItemEvent.SELECTED) {
                    manItemInCombo();
                }
            }
        });
        fontsBox.setModel(new DefaultComboBoxModel(numbers));
        fontsBox.setMaximumRowCount(3);
        add(fontsBox, BorderLayout.CENTER);
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setPreferredSize(new Dimension(400, 60));
        setLocation(200, 105);
        pack();
        setVisible(true);
    }

    private void manItemInCombo() {
        if (fontsBox.getItemCount() > 0) {
            final Object comp = fontsBox.getUI().getAccessibleChild(fontsBox, 0);
            if ((comp instanceof JPopupMenu)) {
                final JList list = new JList(fontsBox.getModel());
                final JPopupMenu popup = (JPopupMenu) comp;
                final JScrollPane scrollPane = (JScrollPane) popup.getComponent(0);
                final JViewport viewport = scrollPane.getViewport();
                final Rectangle rect = popup.getVisibleRect();
                Point pt = viewport.getViewPosition();
                for (int i = 0; i < list.getModel().getSize(); i++) {
                    pt = list.indexToLocation(i);
                    System.out.print(pt + " - ");
                    rect.setLocation(rect.x - pt.x, rect.y - pt.y);
                    System.out.println(new Rectangle(viewport.getExtentSize()).contains(rect));
                }
            }
        }
    }

    public static void main(String arg[]) {
        java.awt.EventQueue.invokeLater(new Runnable() {

            @Override
            public void run() {
                ItemVisibleRecCombo ivrc = new ItemVisibleRecCombo();
            }
        });
    }
}
import java.awt.*;
导入java.awt.event.*;
导入javax.swing.*;
公共类ItemVisibleRecCombo扩展了JFrame{
私有静态最终长serialVersionUID=1L;
私人JComboBox-fontsBox;
公共项VisibleRecCombo(){
字符串[]数字={“一”、“二”、“三”、“四”、“五”、“六”、“七”};
fontsBox=新的JComboBox(数字);
fontsBox.setSelectedItem(0);
addItemListener(新的ItemListener(){
@凌驾
公共无效itemStateChanged(ItemEvent e){
如果(如getStateChange()==ItemEvent.SELECTED){
manItemInCombo();
}
}
});
setModel(新的DefaultComboxModel(数字));
fontsBox.setMaximumRowCount(3);
添加(fontsBox,BorderLayout.CENTER);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setPreferredSize(新尺寸(400,60));
设定位置(200105);
包装();
setVisible(真);
}
私有void manItemInCombo(){
如果(fontsBox.getItemCount()>0){
最终对象comp=fontsBox.getUI().getAccessibleChild(fontsBox,0);
if((JPOPUPMENUS的组件实例)){
最终JList列表=新JList(fontsBox.getModel());
最终JPopupMenu弹出窗口=(JPopupMenu)组件;
最终JScrollPane scrollPane=(JScrollPane)popup.getComponent(0);
final JViewport viewport=scrollPane.getViewport();
最终矩形rect=popup.getVisibleRect();
点pt=viewport.getViewPosition();
对于(int i=0;i
基本上,您正在查找list.locationToIndex(如果我理解正确的话),例如

    Accessible a = fontsBox.getUI().getAccessibleChild(fontsBox, 0);
    if (a instanceof javax.swing.plaf.basic.ComboPopup) {
        JList list = ((javax.swing.plaf.basic.ComboPopup)a).getList();
        Rectangle rect = list.getVisibleRect();
        int first = list.locationToIndex(rect.getLocation());
        // similar for last, at the lower edge of the visible rect, left as exercise <g>
        // Edit: as of @Boro's comment, last is easier calculated with maxRowCount
        int last = first + fontsBox.getMaximumRowCount() - 1;
        ....

回答以下问题:第一个/最后一个(含)之间的所有项目均可见,第一个和最后一个以下的所有项目均不可见;-)

如果要获取在您的组合框中可见的元素,我这里有一个算法,您可以使用它

                Point pt = viewport.getViewPosition();
                int rowCount = fontsBox.getMaximumRowCount();
                int rowsize = viewport.getSize().height / rowCount;
                System.out.println("viewport.getHeight()="+ viewport.getHeight()
                        +"; viewport.getViewSize().getHeight()="+ viewport.getViewSize().getHeight()
                        +"; rowsize=" + rowsize+"; pt="+pt);                
                int firstVisibleElementIndex = pt.y/rowsize;
                int lastVisibleElementIndex = firstVisibleElementIndex + (rowCount-1);
                System.out.println("firstVisibleElementIndex="+ firstVisibleElementIndex
                        +"; lastVisibleElementIndex="+lastVisibleElementIndex);
检查它,它返回您第一个和最后一个可见元素,然后由您决定您希望如何使用它们


编辑:这只是在给定示例基础上构建的一个快速解决方案。有关更好的解决方案,请参阅@kleopatra的解决方案。

谢谢,但您的假设不正确,这是输出,但我无法测试视口是否正确包含项,不可能,我必须返回到我的原始声明,因为它正确地显示了第一个可见项

编辑感谢@Anthony Accioly提供正确的建议
将侦听器从ItemListener更改为ActionListener

1stIndex = 0, LastIndex = 2, SelectedItem1 = two, Value = one, two, three
1stIndex = 0, LastIndex = 2, SelectedItem1 = three, Value = one, two, three
1stIndex = 1, LastIndex = 3, SelectedItem1 = four, Value = two, three, four
1stIndex = 2, LastIndex = 4, SelectedItem1 = five, Value = three, four, five
1stIndex = 3, LastIndex = 5, SelectedItem1 = six, Value = four, five, six
1stIndex = 4, LastIndex = 6, SelectedItem1 = seven, Value = five, six, seven
1stIndex = 4, LastIndex = 6, SelectedItem1 = six, Value = five, six, seven
1stIndex = 4, LastIndex = 6, SelectedItem1 = five, Value = five, six, seven
1stIndex = 3, LastIndex = 5, SelectedItem1 = four, Value = four, five, six
1stIndex = 2, LastIndex = 4, SelectedItem1 = three, Value = three, four, five
1stIndex = 1, LastIndex = 3, SelectedItem1 = two, Value = two, three, four
1stIndex = 0, LastIndex = 2, SelectedItem1 = one, Value = one, two, three
ItemListener的输出错误

1stIndex = 0, LastIndex = 2, SelectedItem1 = two, Value = one, two, three//ok
1stIndex = 0, LastIndex = 2, SelectedItem1 = three, Value = one, two, three//ok
1stIndex = 0, LastIndex = 2, SelectedItem1 = four, Value = one, two, three//wrong
1stIndex = 1, LastIndex = 3, SelectedItem1 = five, Value = two, three, four//wrong
1stIndex = 2, LastIndex = 4, SelectedItem1 = six, Value = three, four, five//wrong
1stIndex = 3, LastIndex = 5, SelectedItem1 = seven, Value = four, five, six//wrong
1stIndex = 4, LastIndex = 6, SelectedItem1 = six, Value = five, six, seven//ok
1stIndex = 4, LastIndex = 6, SelectedItem1 = five, Value = five, six, seven//ok
1stIndex = 4, LastIndex = 6, SelectedItem1 = four, Value = five, six, seven//wrong
1stIndex = 3, LastIndex = 5, SelectedItem1 = three, Value = four, five, six//wrong
1stIndex = 2, LastIndex = 4, SelectedItem1 = two, Value = three, four, five//wrong
1stIndex = 1, LastIndex = 3, SelectedItem1 = one, Value = two, three, four//wrong
以及
ActionListener的预期输出

1stIndex = 0, LastIndex = 2, SelectedItem1 = two, Value = one, two, three
1stIndex = 0, LastIndex = 2, SelectedItem1 = three, Value = one, two, three
1stIndex = 1, LastIndex = 3, SelectedItem1 = four, Value = two, three, four
1stIndex = 2, LastIndex = 4, SelectedItem1 = five, Value = three, four, five
1stIndex = 3, LastIndex = 5, SelectedItem1 = six, Value = four, five, six
1stIndex = 4, LastIndex = 6, SelectedItem1 = seven, Value = five, six, seven
1stIndex = 4, LastIndex = 6, SelectedItem1 = six, Value = five, six, seven
1stIndex = 4, LastIndex = 6, SelectedItem1 = five, Value = five, six, seven
1stIndex = 3, LastIndex = 5, SelectedItem1 = four, Value = four, five, six
1stIndex = 2, LastIndex = 4, SelectedItem1 = three, Value = three, four, five
1stIndex = 1, LastIndex = 3, SelectedItem1 = two, Value = two, three, four
1stIndex = 0, LastIndex = 2, SelectedItem1 = one, Value = one, two, three
编辑代码

import java.awt.*;
import java.awt.event.*;
import javax.accessibility.Accessible;
import javax.swing.*;

public class ItemVisibleRecCombo extends JFrame {

    private static final long serialVersionUID = 1L;
    private JComboBox fontsBox;

    public ItemVisibleRecCombo() {
        String[] numbers = {"one", "two", "three", "four", "five", "six", "seven"};
        fontsBox = new JComboBox(numbers);
        fontsBox.setSelectedItem(0);
        /*fontsBox.addItemListener(new ItemListener() {

        @Override
        public void itemStateChanged(ItemEvent e) {
        if (e.getStateChange() == ItemEvent.SELECTED) {
        manItemInCombo();
        }
        }
        });*/
        fontsBox.addActionListener(new ActionListener() {

            @Override
            public void actionPerformed(ActionEvent e) {
                manItemInCombo();
            }
        });
        fontsBox.setModel(new DefaultComboBoxModel(numbers));
        fontsBox.setMaximumRowCount(3);
        add(fontsBox, BorderLayout.CENTER);
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setPreferredSize(new Dimension(400, 60));
        setLocation(200, 105);
        pack();
        setVisible(true);
    }

    private void manItemInCombo() {
        if (fontsBox.getItemCount() > 0) {
            final Accessible a = fontsBox.getUI().getAccessibleChild(fontsBox, 0);
            if (a instanceof javax.swing.plaf.basic.ComboPopup) {
                final JList list = ((javax.swing.plaf.basic.ComboPopup) a).getList();
                final Rectangle rect = list.getVisibleRect();
                final int first = list.locationToIndex(rect.getLocation());
                final int last = first + fontsBox.getMaximumRowCount() - 1;
                String selectedItem = fontsBox.getSelectedItem().toString();
                System.out.println("1stIndex = " + first + ", LastIndex = "
                        + last + ", SelectedItem1 = " + selectedItem
                        + ", Value = " + fontsBox.getItemAt(first).toString()
                        + ", " + fontsBox.getItemAt(first + 1).toString()
                        + ", " + fontsBox.getItemAt(first + 2).toString());
            }
        }
    }

    public static void main(String arg[]) {
        java.awt.EventQueue.invokeLater(new Runnable() {

            @Override
            public void run() {
                ItemVisibleRecCombo ivrc = new ItemVisibleRecCombo();
            }
        });
    }
}

将侦听器从
itemstener
更改为
ActionListener
似乎可以为箭头键和单击提供预期的结果:

fontsBox.addActionListener(new ActionListener() {

    @Override
    public void actionPerformed(ActionEvent e) {
         manItemInCombo();
    }
});

不,您不需要视口,列表本身告诉您所有这些necessary@kleopatra我刚刚扩展了@mKorbel提供的示例,我并不是说这是最好的/唯一的方法:)不要重复错误的/过于复杂的事情,它们有留在记忆中的倾向;-)@克利奥帕特拉:你完全正确实现我的解决方案,我不认为这是“更干净”的方式,我只是重新使用了代码。是的,这只是和这个线程,因为我想玩/应用渲染器只是在派生的JVIEWPORT中可见的项目,我会检查你的…+ 1更好的更清洁的做事方式。kleopatra不过,要得到最后一个,最好只是计算它,而不是询问列表中需要创建新对象的位置<代码>int rowCount=fontsBox.getMaximumRowCount();int last=first+(行计数-1)
@Boro-第一个答案是否定的:只需移动可见矩形,无需创建(这并不重要,假设是微优化;-)+1使用maxRowCount,将进行编辑:-)你完全正确,我忘记了可见矩形是一个副本,你可以用它做你想要的一切。谢谢。对我(Windows+JavaSE6)来说,只是一个评论,点击这些项目似乎给出了正确的结果,使用箭头我得到了错误的结果@mKorbel,你能确认吗?是的,这是正确的,:-)但是我对直接选择某个项目不感兴趣,因为ItemListener只是模拟MouseListener,如果你用鼠标+ScroolBar滚动,则不会选择任何项目:-)好的。但是在什么样的事件中,您正试图捕获可见的行呢?老鼠进来了?老鼠离开了?鼠标移动?@Anthony Accioly,现在我不知道可能直接
((JViewport)((JScrollPane)((basicmbopopup)field.get(box.getUI()).getComponents()[0]).getComponents()[0]).getComponents()[0].addMouseListener(listener())可能是普通的香草侦听器
fontsBox.add