- iOS/Objective-C 元类和类别
- objective-c - -1001 错误,当 NSURLSession 通过 httpproxy 和/etc/hosts
- java - 使用网络类获取 url 地址
- ios - 推送通知中不播放声音
我正在尝试弄清楚如何将样式功能添加到 JList 以使其正常运行(如果选择了项目则关闭按钮)(如果收到新消息则为新消息图标)就像它在此处完成的那样:
(来源:livechatinc.com)
我在想“安娜、露西和乔”的名单
有什么想法可以实现吗?
编辑:切换到正确的图片:)
最佳答案
有很多方法可以满足您的要求。我真的不能说哪种方式更好 - 使用 JList
,创建您自己的组件,从头开始绘制整个组件或其他方式。
每种方法都有自己的优点和缺点:
JList
渲染速度更快,代码更简洁我真的不认为 JTable
无论如何都会比 JList
更好地帮助您 - 它具有相同的呈现策略。是的,它有编辑器,但像按钮一样使用它们对我来说似乎有点奇怪。
在使用 JList
渲染器玩了大约 15-20 分钟后,我从您的屏幕截图中复制了列表的完整副本(图标除外 - 我只是选择了自己的)。这是下面列出的示例的屏幕截图:
JList
实际上是一个非常强大的工具,如果您知道如何使用它的话。
这是该示例的源代码:
import javax.swing.*;
import java.awt.*;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.geom.Area;
import java.awt.geom.Ellipse2D;
import java.awt.geom.RoundRectangle2D;
/**
* @author Mikle Garin
* @see http://stackoverflow.com/a/18589264/909085
*/
public class CustomListRenderer extends DefaultListCellRenderer
{
private static final ImageIcon crossIcon = new ImageIcon ( CustomListRenderer.class.getResource ( "cross.png" ) );
private static final ImageIcon tipIcon = new ImageIcon ( CustomListRenderer.class.getResource ( "tip.png" ) );
/**
* Sample frame with list.
*
* @param args arguments
*/
public static void main ( String[] args )
{
JFrame frame = new JFrame ( "Custom list renderer" );
DefaultListModel model = new DefaultListModel ();
model.addElement ( new CustomData ( new Color ( 209, 52, 23 ), 1, "Anna Williams" ) );
model.addElement ( new CustomData ( new Color ( 135, 163, 14 ), 0, "Lucy Frank" ) );
model.addElement ( new CustomData ( new Color ( 204, 204, 204 ), 0, "Joe Fritz" ) );
model.addElement ( new CustomData ( new Color ( 90, 90, 90 ), 3, "Mikle Garin" ) );
JList list = new JList ( model );
list.setCellRenderer ( new CustomListRenderer ( list ) );
list.setBorder ( BorderFactory.createEmptyBorder ( 5, 5, 5, 5 ) );
frame.add ( list );
frame.pack ();
frame.setLocationRelativeTo ( null );
frame.setDefaultCloseOperation ( JFrame.EXIT_ON_CLOSE );
frame.setVisible ( true );
}
/**
* Actual renderer.
*/
private CustomLabel renderer;
/**
* Custom renderer constructor.
* We will use it to create actual renderer component instance.
* We will also add a custom mouse listener to process close button.
*
* @param list our JList instance
*/
public CustomListRenderer ( final JList list )
{
super ();
renderer = new CustomLabel ();
list.addMouseListener ( new MouseAdapter ()
{
@Override
public void mouseReleased ( MouseEvent e )
{
if ( SwingUtilities.isLeftMouseButton ( e ) )
{
int index = list.locationToIndex ( e.getPoint () );
if ( index != -1 && list.isSelectedIndex ( index ) )
{
Rectangle rect = list.getCellBounds ( index, index );
Point pointWithinCell = new Point ( e.getX () - rect.x, e.getY () - rect.y );
Rectangle crossRect = new Rectangle ( rect.width - 9 - 5 - crossIcon.getIconWidth () / 2,
rect.height / 2 - crossIcon.getIconHeight () / 2, crossIcon.getIconWidth (), crossIcon.getIconHeight () );
if ( crossRect.contains ( pointWithinCell ) )
{
DefaultListModel model = ( DefaultListModel ) list.getModel ();
model.remove ( index );
}
}
}
}
} );
}
/**
* Returns custom renderer for each cell of the list.
*
* @param list list to process
* @param value cell value (CustomData object in our case)
* @param index cell index
* @param isSelected whether cell is selected or not
* @param cellHasFocus whether cell has focus or not
* @return custom renderer for each cell of the list
*/
@Override
public Component getListCellRendererComponent ( JList list, Object value, int index, boolean isSelected, boolean cellHasFocus )
{
renderer.setSelected ( isSelected );
renderer.setData ( ( CustomData ) value );
return renderer;
}
/**
* Label that has some custom decorations.
*/
private static class CustomLabel extends JLabel
{
private static final Color selectionColor = new Color ( 82, 158, 202 );
private boolean selected;
private CustomData data;
public CustomLabel ()
{
super ();
setOpaque ( false );
setBorder ( BorderFactory.createEmptyBorder ( 0, 36 + 5, 0, 40 ) );
}
private void setSelected ( boolean selected )
{
this.selected = selected;
setForeground ( selected ? Color.WHITE : Color.BLACK );
}
private void setData ( CustomData data )
{
this.data = data;
setText ( data.getName () );
}
@Override
protected void paintComponent ( Graphics g )
{
Graphics2D g2d = ( Graphics2D ) g;
g2d.setRenderingHint ( RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON );
if ( selected )
{
Area area = new Area ( new Ellipse2D.Double ( 0, 0, 36, 36 ) );
area.add ( new Area ( new RoundRectangle2D.Double ( 18, 3, getWidth () - 18, 29, 6, 6 ) ) );
g2d.setPaint ( selectionColor );
g2d.fill ( area );
g2d.setPaint ( Color.WHITE );
g2d.fill ( new Ellipse2D.Double ( 2, 2, 32, 32 ) );
}
g2d.setPaint ( data.getCircleColor () );
g2d.fill ( new Ellipse2D.Double ( 5, 5, 26, 26 ) );
g2d.drawImage ( tipIcon.getImage (), 5 + 13 - tipIcon.getIconWidth () / 2, 5 + 13 - tipIcon.getIconHeight () / 2, null );
if ( selected )
{
g2d.drawImage ( crossIcon.getImage (), getWidth () - 9 - 5 - crossIcon.getIconWidth () / 2,
getHeight () / 2 - crossIcon.getIconHeight () / 2, null );
}
else if ( data.getNewMessages () > 0 )
{
g2d.setPaint ( selectionColor );
g2d.fill ( new Ellipse2D.Double ( getWidth () - 18 - 5, getHeight () / 2 - 9, 18, 18 ) );
final String text = "" + data.getNewMessages ();
final Font oldFont = g2d.getFont ();
g2d.setFont ( oldFont.deriveFont ( oldFont.getSize () - 1f ) );
final FontMetrics fm = g2d.getFontMetrics ();
g2d.setPaint ( Color.WHITE );
g2d.drawString ( text, getWidth () - 9 - 5 - fm.stringWidth ( text ) / 2,
getHeight () / 2 + ( fm.getAscent () - fm.getLeading () - fm.getDescent () ) / 2 );
g2d.setFont ( oldFont );
}
super.paintComponent ( g );
}
@Override
public Dimension getPreferredSize ()
{
final Dimension ps = super.getPreferredSize ();
ps.height = 36;
return ps;
}
}
/**
* Custom data for our list.
*/
private static class CustomData
{
private Color circleColor;
private int newMessages;
private String name;
public CustomData ( Color circleColor, int newMessages, String name )
{
super ();
this.circleColor = circleColor;
this.newMessages = newMessages;
this.name = name;
}
private Color getCircleColor ()
{
return circleColor;
}
private int getNewMessages ()
{
return newMessages;
}
private String getName ()
{
return name;
}
}
}
是的,此示例需要一些 Graphics2D
的高级知识,否则您将无法完全模仿源示例。但无论如何,如果您想最终创建一些非常好的 UI,那正是您必须知道的。
无论如何,在这种情况下,JList
的唯一问题是用于渲染单元格的组件不是“Activity 的”,这意味着您可以将一些按钮放入渲染器中,但它不会起作用作为一个按钮 - 它最终将是该按钮的一个简单图像。当然,您不会从此类按钮收到任何事件。
您还可以在列表中看到 10 个按钮(例如,如果您在列表中有 10 个单元格),但只有一个具有不同设置的真实按钮将用于呈现所有这些单元格 - 这是主要优化JList
- 它不会为每个单元格创建大量组件,它会为每个单元格重复使用单个渲染器。
因此,您必须将自己的鼠标监听器添加到列表中,并处理列表中鼠标事件的坐标(这实际上并不难)。我在上面发布的示例中做到了这一点 - 小型鼠标监听器捕捉十字“按钮”上的点击。
请注意,列表有其自己的用于选择单元格的鼠标监听器 - 您必须与这些监听器“协作”以避免您自己的列表中出现任何不当行为。
附言我差点忘了,这是我用过的两个图标:< > < >
第二个是白色的(十字图标),所以我用大括号突出显示了它 - 不要错过它! :)
关于用于聊天的 Java 样式 JList,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18576612/
我在为 MacOSX 构建的独立包中添加 DMG 背景的自定义图标时遇到问题。我在项目的根目录中添加了一个包。正在从中加载自定义图标,但没有加载 DMG 背景图标。我正在使用 Java fx 2.2.
Qt for Symbian 和 Qt for MeeGo 有什么区别?我知道 Qt 是一个交叉编译平台。这是否意味着如果我使用来自 Qt 的库,完全相同的库可以在所有支持 Qt 的设备(例如 Sym
我正在尝试使用 C# .NET 3.5/4.0 务实地运行 SQL Server 数据库的备份。我已经找到了如何完成此操作,但是我似乎找不到用于备份的命名空间库。 我正在寻找 Microsoft.Sq
我最近在疯狂学习 Java,但我通常是一名 .NET 开发人员。 (所以请原谅我的新手问题。) 在 .Net 中,我可以在不使用 IIS 的情况下开发 ASP.Net 页面,因为它有一个简化的 Web
这post仅当打印命令中有字符串时才有用。现在我有大量的源代码,其中包含一条声明,例如 print milk,butter 应该格式化为 print(milk,butter) 用\n 捕获行尾并不成功
所以我的问题是: https://gist.github.com/panSarin/4a221a0923927115584a 当我保存这个表格时,我收到了标题中的错误 NoMethodError (u
如何让 Html5 音频在点击时播放声音? (ogg 用于 Firefox 等浏览器,mp3 用于 chrome 等浏览器) 到目前为止,我可以通过 onclick 更改为单个文件类型,但我无法像在普
如果it1和it2有什么区别? std::set s; auto it1 = std::inserter(s, s.begin()); auto it2 = std::inserter(s, s.en
4.0.0 com.amkit myapp SpringMVCFirst
我目前使用 Eclipse 作为其他语言的 IDE,而且我习惯于不必离开 IDE 做任何事情 - 但是我真的很难为纯 ECMAScript-262 找到相同或类似的设置。 澄清一下,我不是在寻找 DO
我想将带有字符串数组的C# 结构发送到C++ 函数,该函数接受void * 作为c# 结构和char** 作为c# 结构字符串数组成员。 我能够将结构发送到 c++ 函数,但问题是,无法从 c++ 函
我正在使用动态创建的链接: 我想为f:param附加自定义转换器,以从#{name}等中删除空格。 但是f:param中没有转换器
是否可以利用Redis为.NET创建后写或直写式缓存?理想情况下,透明的高速缓存是由单个进程写入的,并且支持从数据库加载丢失的数据,并每隔一段时间持久保存脏块? 我已经搜查了好几个小时,也许是goog
我正在通过bash执行命令的ssh脚本。 FILENAMES=( "export_production_20200604.tgz" "export_production_log_2020060
我需要一个正则表达式来出现 0 到 7 个字母或 0 到 7 个数字。 例如:匹配:1234、asdbs 不匹配:123456789、absbsafsfsf、asf12 我尝试了([a-zA-Z]{0
我有一个用于会计期间的表格,该表格具有期间结束和开始的开始日期和结束日期。我使用此表来确定何时发生服务交易以及何时在查询中收集收入,例如... SELECT p.PeriodID, p.FiscalY
我很难为只接受字符或数字的 Laravel 构建正则表达式验证。它是这样的: 你好<-好的 123 <- 好的 你好123 <-不行 我现在的正则表达式是这样的:[A-Za-z]|[0-9]。 reg
您实际上会在 Repeater 上使用 OnItemDataBound 做什么? 最佳答案 “此事件为您提供在客户端显示数据项之前访问数据项的最后机会。引发此事件后,数据项将被清空,不再可用。” ~
我有一个 fragment 工作正常的项目,我正在使用 jeremyfeinstein 的 actionbarsherlock 和滑动菜单, 一切正常,但是当我想自定义左侧抽屉列表单元格时,出现异常
最近几天,我似乎平均分配时间在构建我的第一个应用程序和在这里发布问题!! 这是我的第一个应用程序,也是我们的设计师完成的第一个应用程序。我试图满足他所做的事情的外观和感觉,但我认为他没有做适当的事情。
我是一名优秀的程序员,十分优秀!