如何单独更改每个 controlP5 下拉列表条目的颜色?
How to change color of each controlP5 dropdown list entry individually?
使用以下 MWE:
import controlP5.*;
import java.util.*;
ControlP5 cp5;
void setup() {
size(400, 400);
cp5 = new ControlP5(this);
List l = Arrays.asList("a", "b", "c", "d", "e", "f", "g", "h");
/* add a ScrollableList, by default it behaves like a DropdownList */
cp5.addScrollableList("dropdown")
.setPosition(100, 100)
.setSize(200, 100)
.setBarHeight(20)
.setItemHeight(20)
.addItems(l)
// .setType(ScrollableList.LIST) // currently supported DROPDOWN and LIST
;
}
void draw() {
background(240);
}
如何分别更改每个列表条目的字体颜色?我假设我必须使用类似下面的某种 for 循环
for (int i =0; i < myarray.length; i++){
dropdown.setColorActive(elementDetermine(myarray[i]));
}
其中 elementDetermine() 接受一个整数和 returns 一种颜色。不幸的是,当我 运行 在设置或绘图函数中循环时,下拉列表不会在没有错误消息的情况下发生变化。
遗憾的是,没有简单易行的方法来单独更改每个列表条目的字体颜色。
如您在 documentation 中所见,可用方法访问适用于所有项目的主标题。
事实上,相同的 Label
组件在所有列表项中 re-used 并且每个项仅 re-rendered 一次(更改当前 text/colours),如您所见source code
如果你真的真的需要改变字体颜色,你可以,但是要跳过很多 OOP 环节(因为每个项目没有 Label
个实例的数组):
- 您需要自定义
ControllerView< ScrollableList >
来覆盖它的 display()
方法
- 为了使自定义
display()
与原始 ScrollableList 一样工作,您需要几乎复制超级 class
-
ScrollableList
super class 有一堆私有属性可以很容易地从 ScrollableListView
class 访问,因为它是 ScrollableList
的一部分,但是在我们的例子中,所有需要在 display()
中访问的 private
/ protected
属性都需要可访问。为此,实现了 ScrollableList
subclass (PopUpScrollableList
),它主要复制它的 superclass 行为,无论这些 private
/protected
属性在哪里在 display()
中使用并使它们可用。
最后,自定义可滚动列表可以有一个 color[]
,它可以存储自定义颜色,以便可以在覆盖的 display()
方法中访问和呈现它们:
import controlP5.*;
// used by the custom scrollable list view
import static controlP5.ControlP5.b;
import java.util.*;
ControlP5 cp5;
void setup() {
size(400, 400);
cp5 = new ControlP5(this);
List l = Arrays.asList("a", "b", "c", "d", "e", "f", "g", "h");
/* add a custom ScrollableList, by default it behaves like a DropdownList */
PopUpScrollableList dropdown = addPopUpScrollableList("dropdown");
dropdown.setPosition(100, 100)
.setSize(200, 100)
.setBarHeight(20)
.setItemHeight(20)
.addItems(l)
// .setType(ScrollableList.LIST) // currently supported DROPDOWN and LIST
;
// a list of (random) colourr: a colour per item
color[] textColors = new color[l.size()];
for(int i = 0 ; i < textColors.length; i++){
textColors[i] = color(255, random(255), random(255), random(255));
}
// set custom text colours: this is a bit hacky: normally you'd check if items.size() matches textColors.length, etc.
dropdown.textColors = textColors;
// set a custom view for the list
dropdown.setView(makeCustomScrollListView());
}
void draw() {
background(240);
}
// simply adds our custom scrollable list
PopUpScrollableList addPopUpScrollableList( final String theName ) {
PopUpScrollableList myController = new PopUpScrollableList(cp5, theName);
return myController;
}
ControllerView< ScrollableList > makeCustomScrollListView(){
// make an custom scrollable list view on the fly and access the fileds it needs
return new ControllerView< ScrollableList >() {
// tweaked version of https://github.com/sojamo/controlp5/blob/1f7cb649865eb8657495b5cfeddd0dbe85d70cac/src/controlP5/ScrollableList.java#L391
public void display( PGraphics g , ScrollableList c ) {
// setHeight( -200 ); /* UP */
PopUpScrollableList d = (PopUpScrollableList)c;
g.noStroke( );
if ( c.isBarVisible( ) ) {
boolean b = d.itemHover() == -1 && d.isInside() && !d.isDragged();
g.fill( b ? c.getColor( ).getForeground( ) : c.getColor( ).getBackground( ) );
g.rect( 0 , 0 , c.getWidth( ) , c.getBarHeight() );
g.pushMatrix( );
g.translate( c.getWidth( ) - 8 , c.getBarHeight() / 2 - 2 );
g.fill( c.getColor( ).getCaptionLabel( ) );
if ( c.isOpen( ) ) {
g.triangle( -3 , 0 , 3 , 0 , 0 , 3 );
} else {
g.triangle( -3 , 3 , 3 , 3 , 0 , 0 );
}
g.popMatrix( );
c.getCaptionLabel( ).draw( g , 4 , c.getBarHeight() / 2 );
}
if ( c.isOpen( ) ) {
int bar = ( c.isBarVisible( ) ? c.getBarHeight() : 0 );
int h = ( ( d.updateHeight( ) ) );
g.pushMatrix( );
// g.translate( 0 , - ( h + bar +
// c.itemSpacing ) ); /* UP */
g.fill( c.getBackgroundColor( ) );
g.rect( 0 , bar , c.getWidth( ) , h );
g.pushMatrix( );
g.translate( 0 , ( bar == 0 ? 0 : ( c.getBarHeight() + d.itemSpacing() ) ) );
/* draw visible items */
c.updateItemIndexOffset( );
int m0 = d.itemIndexOffset;
List items = c.getItems();
int m1 = items.size( ) > d.itemRange() ? ( d.itemIndexOffset + d.itemRange() ) : items.size( );
for ( int i = m0 ; i < m1 ; i++ ) {
Map< String , Object > item = (Map< String , Object >) items.get( i );
CColor itemColor = ( CColor ) item.get( "color" );
g.fill( ( b( item.get( "state" ) ) ) ? itemColor.getActive( ) : ( i == d.itemHover() ) ? ( c.isMousePressed() ? itemColor.getActive( ) : itemColor.getForeground( ) ) : itemColor.getBackground( ) );
float boxY = d.itemHeight() - 1;
g.rect( 0 , 0 , c.getWidth( ) , boxY );
Label label = c.getValueLabel( );
// finally set custom text colour
if(d.textColors != null){
label.setColor(d.textColors[i]);
}
label.set( item.get( "text" ).toString( ) ).draw( g , 4 , d.itemHeight() / 2 );
g.translate( 0 , d.itemHeight() );
}
g.popMatrix( );
if ( c.isInside() ) {
int m = items.size( ) - d.itemRange();
if ( m > 0 ) {
g.fill( c.getColor( ).getCaptionLabel( ) );
g.pushMatrix( );
int s = 4; /* spacing */
int s2 = s / 2;
g.translate( c.getWidth( ) - s , c.getBarHeight() );
int len = ( int ) PApplet.map( ( float ) Math.log( m * 10 ) , 0 , 10 , h , 0 );
int pos = ( int ) ( PApplet.map( d.itemIndexOffset , 0 , m , s2 , h - len - s2 ) );
g.rect( 0 , pos , s2 , len );
g.popMatrix( );
}
}
g.popMatrix( );
}
}
};
}
// a custom ScrollableList subclass: mainly it needs to expose properties the custom view (via setView()) can't access in display()
class PopUpScrollableList extends ScrollableList{
private int itemIndexOffset = 0;
private int _myType = DROPDOWN;
protected boolean isOpen = true;
public color[] textColors;
PopUpScrollableList(ControlP5 cp5, String name){
super(cp5, name);
println("custom PopUpScrollableList named " + name + " constructed");
}
public boolean isOpen( ) {
return isOpen;
}
public ScrollableList open( ) {
return setOpen( true );
}
public ScrollableList close( ) {
return setOpen( false );
}
public ScrollableList setOpen( boolean b ) {
isOpen = b;
return this;
}
public int itemHover(){
return itemHover;
}
public int itemSpacing(){
return 1;
}
public int itemRange(){
return itemRange;
}
public int itemHeight(){
return itemHeight;
}
public boolean isInside(){
return isInside;
}
public boolean isDragged(){
return isDragged;
}
public int barHeight(){
return barHeight;
}
protected int updateHeight( ) {
itemRange = ( PApplet.abs( getHeight( ) ) - ( isBarVisible( ) ? barHeight : 0 ) ) / itemHeight;
return itemHeight * ( items.size( ) < itemRange ? items.size( ) : itemRange );
}
public List< Map< String , Object > > items(){
return items;
}
@Override protected void onRelease( ) {
if ( !isDragged ) {
if ( getPointer( ).y( ) >= 0 && getPointer( ).y( ) <= barHeight ) {
setOpen( !isOpen( ) );
} else if ( isOpen ) {
double n = Math.floor( ( getPointer( ).y( ) - barHeight ) / itemHeight );
// n += itemRange; /* UP */
int index = ( int ) n + itemIndexOffset;
updateIndex( index );
}
}
}
private void updateIndex( int theIndex ) {
if ( theIndex >= items.size( ) ) {
return;
}
Map m = items.get( theIndex );
switch ( _myType ) {
case ( LIST ):
super.setValue( theIndex );
for ( Object o : items ) {
( ( Map ) o ).put( "state" , false );
}
m.put( "state" , !ControlP5.b( m.get( "state" ) ) );
break;
case ( DROPDOWN ):
super.setValue( theIndex );
setOpen( false );
getCaptionLabel( ).setText( ( m.get( "text" ).toString( ) ) );
break;
case ( CHECKBOX ):
m.put( "state" , !ControlP5.b( m.get( "state" ) ) );
break;
}
}
public ScrollableList setValue( float theValue ) {
updateIndex( ( int ) ( theValue ) );
return this;
}
@Override protected void onDrag( ) {
scroll( getPointer( ).dy( ) );
}
@Override protected void onScroll( int theValue ) {
scroll( theValue );
}
private void scroll( int theValue ) {
if ( isOpen() ) {
itemIndexOffset += theValue;
itemIndexOffset = ( int ) ( Math.floor( Math.max( 0 , Math.min( itemIndexOffset , items.size( ) - itemRange ) ) ) );
itemHover = -2;
}
}
@Override protected void onLeave( ) {
itemHover = -1;
}
@Override protected void onEnter( ) {
updateHover( );
}
@Override protected void onMove( ) {
updateHover( );
}
@Override protected void onEndDrag( ) {
updateHover( );
}
private void updateHover( ) {
if ( getPointer( ).y( ) > barHeight ) {
double n = Math.floor( ( getPointer( ).y( ) - barHeight ) / itemHeight );
itemHover = ( int ) ( itemIndexOffset + n );
} else {
itemHover = -1;
}
}
public void updateItemIndexOffset( ) {
int m1 = items.size( ) > itemRange ? ( itemIndexOffset + itemRange ) : items.size( );
int n = ( m1 - items.size( ) );
if ( n >= 0 ) {
itemIndexOffset -= n;
}
}
}
使用以下 MWE:
import controlP5.*;
import java.util.*;
ControlP5 cp5;
void setup() {
size(400, 400);
cp5 = new ControlP5(this);
List l = Arrays.asList("a", "b", "c", "d", "e", "f", "g", "h");
/* add a ScrollableList, by default it behaves like a DropdownList */
cp5.addScrollableList("dropdown")
.setPosition(100, 100)
.setSize(200, 100)
.setBarHeight(20)
.setItemHeight(20)
.addItems(l)
// .setType(ScrollableList.LIST) // currently supported DROPDOWN and LIST
;
}
void draw() {
background(240);
}
如何分别更改每个列表条目的字体颜色?我假设我必须使用类似下面的某种 for 循环
for (int i =0; i < myarray.length; i++){
dropdown.setColorActive(elementDetermine(myarray[i]));
}
其中 elementDetermine() 接受一个整数和 returns 一种颜色。不幸的是,当我 运行 在设置或绘图函数中循环时,下拉列表不会在没有错误消息的情况下发生变化。
遗憾的是,没有简单易行的方法来单独更改每个列表条目的字体颜色。
如您在 documentation 中所见,可用方法访问适用于所有项目的主标题。
事实上,相同的 Label
组件在所有列表项中 re-used 并且每个项仅 re-rendered 一次(更改当前 text/colours),如您所见source code
如果你真的真的需要改变字体颜色,你可以,但是要跳过很多 OOP 环节(因为每个项目没有 Label
个实例的数组):
- 您需要自定义
ControllerView< ScrollableList >
来覆盖它的display()
方法 - 为了使自定义
display()
与原始 ScrollableList 一样工作,您需要几乎复制超级 class -
ScrollableList
super class 有一堆私有属性可以很容易地从ScrollableListView
class 访问,因为它是ScrollableList
的一部分,但是在我们的例子中,所有需要在display()
中访问的private
/protected
属性都需要可访问。为此,实现了ScrollableList
subclass (PopUpScrollableList
),它主要复制它的 superclass 行为,无论这些private
/protected
属性在哪里在display()
中使用并使它们可用。
最后,自定义可滚动列表可以有一个 color[]
,它可以存储自定义颜色,以便可以在覆盖的 display()
方法中访问和呈现它们:
import controlP5.*;
// used by the custom scrollable list view
import static controlP5.ControlP5.b;
import java.util.*;
ControlP5 cp5;
void setup() {
size(400, 400);
cp5 = new ControlP5(this);
List l = Arrays.asList("a", "b", "c", "d", "e", "f", "g", "h");
/* add a custom ScrollableList, by default it behaves like a DropdownList */
PopUpScrollableList dropdown = addPopUpScrollableList("dropdown");
dropdown.setPosition(100, 100)
.setSize(200, 100)
.setBarHeight(20)
.setItemHeight(20)
.addItems(l)
// .setType(ScrollableList.LIST) // currently supported DROPDOWN and LIST
;
// a list of (random) colourr: a colour per item
color[] textColors = new color[l.size()];
for(int i = 0 ; i < textColors.length; i++){
textColors[i] = color(255, random(255), random(255), random(255));
}
// set custom text colours: this is a bit hacky: normally you'd check if items.size() matches textColors.length, etc.
dropdown.textColors = textColors;
// set a custom view for the list
dropdown.setView(makeCustomScrollListView());
}
void draw() {
background(240);
}
// simply adds our custom scrollable list
PopUpScrollableList addPopUpScrollableList( final String theName ) {
PopUpScrollableList myController = new PopUpScrollableList(cp5, theName);
return myController;
}
ControllerView< ScrollableList > makeCustomScrollListView(){
// make an custom scrollable list view on the fly and access the fileds it needs
return new ControllerView< ScrollableList >() {
// tweaked version of https://github.com/sojamo/controlp5/blob/1f7cb649865eb8657495b5cfeddd0dbe85d70cac/src/controlP5/ScrollableList.java#L391
public void display( PGraphics g , ScrollableList c ) {
// setHeight( -200 ); /* UP */
PopUpScrollableList d = (PopUpScrollableList)c;
g.noStroke( );
if ( c.isBarVisible( ) ) {
boolean b = d.itemHover() == -1 && d.isInside() && !d.isDragged();
g.fill( b ? c.getColor( ).getForeground( ) : c.getColor( ).getBackground( ) );
g.rect( 0 , 0 , c.getWidth( ) , c.getBarHeight() );
g.pushMatrix( );
g.translate( c.getWidth( ) - 8 , c.getBarHeight() / 2 - 2 );
g.fill( c.getColor( ).getCaptionLabel( ) );
if ( c.isOpen( ) ) {
g.triangle( -3 , 0 , 3 , 0 , 0 , 3 );
} else {
g.triangle( -3 , 3 , 3 , 3 , 0 , 0 );
}
g.popMatrix( );
c.getCaptionLabel( ).draw( g , 4 , c.getBarHeight() / 2 );
}
if ( c.isOpen( ) ) {
int bar = ( c.isBarVisible( ) ? c.getBarHeight() : 0 );
int h = ( ( d.updateHeight( ) ) );
g.pushMatrix( );
// g.translate( 0 , - ( h + bar +
// c.itemSpacing ) ); /* UP */
g.fill( c.getBackgroundColor( ) );
g.rect( 0 , bar , c.getWidth( ) , h );
g.pushMatrix( );
g.translate( 0 , ( bar == 0 ? 0 : ( c.getBarHeight() + d.itemSpacing() ) ) );
/* draw visible items */
c.updateItemIndexOffset( );
int m0 = d.itemIndexOffset;
List items = c.getItems();
int m1 = items.size( ) > d.itemRange() ? ( d.itemIndexOffset + d.itemRange() ) : items.size( );
for ( int i = m0 ; i < m1 ; i++ ) {
Map< String , Object > item = (Map< String , Object >) items.get( i );
CColor itemColor = ( CColor ) item.get( "color" );
g.fill( ( b( item.get( "state" ) ) ) ? itemColor.getActive( ) : ( i == d.itemHover() ) ? ( c.isMousePressed() ? itemColor.getActive( ) : itemColor.getForeground( ) ) : itemColor.getBackground( ) );
float boxY = d.itemHeight() - 1;
g.rect( 0 , 0 , c.getWidth( ) , boxY );
Label label = c.getValueLabel( );
// finally set custom text colour
if(d.textColors != null){
label.setColor(d.textColors[i]);
}
label.set( item.get( "text" ).toString( ) ).draw( g , 4 , d.itemHeight() / 2 );
g.translate( 0 , d.itemHeight() );
}
g.popMatrix( );
if ( c.isInside() ) {
int m = items.size( ) - d.itemRange();
if ( m > 0 ) {
g.fill( c.getColor( ).getCaptionLabel( ) );
g.pushMatrix( );
int s = 4; /* spacing */
int s2 = s / 2;
g.translate( c.getWidth( ) - s , c.getBarHeight() );
int len = ( int ) PApplet.map( ( float ) Math.log( m * 10 ) , 0 , 10 , h , 0 );
int pos = ( int ) ( PApplet.map( d.itemIndexOffset , 0 , m , s2 , h - len - s2 ) );
g.rect( 0 , pos , s2 , len );
g.popMatrix( );
}
}
g.popMatrix( );
}
}
};
}
// a custom ScrollableList subclass: mainly it needs to expose properties the custom view (via setView()) can't access in display()
class PopUpScrollableList extends ScrollableList{
private int itemIndexOffset = 0;
private int _myType = DROPDOWN;
protected boolean isOpen = true;
public color[] textColors;
PopUpScrollableList(ControlP5 cp5, String name){
super(cp5, name);
println("custom PopUpScrollableList named " + name + " constructed");
}
public boolean isOpen( ) {
return isOpen;
}
public ScrollableList open( ) {
return setOpen( true );
}
public ScrollableList close( ) {
return setOpen( false );
}
public ScrollableList setOpen( boolean b ) {
isOpen = b;
return this;
}
public int itemHover(){
return itemHover;
}
public int itemSpacing(){
return 1;
}
public int itemRange(){
return itemRange;
}
public int itemHeight(){
return itemHeight;
}
public boolean isInside(){
return isInside;
}
public boolean isDragged(){
return isDragged;
}
public int barHeight(){
return barHeight;
}
protected int updateHeight( ) {
itemRange = ( PApplet.abs( getHeight( ) ) - ( isBarVisible( ) ? barHeight : 0 ) ) / itemHeight;
return itemHeight * ( items.size( ) < itemRange ? items.size( ) : itemRange );
}
public List< Map< String , Object > > items(){
return items;
}
@Override protected void onRelease( ) {
if ( !isDragged ) {
if ( getPointer( ).y( ) >= 0 && getPointer( ).y( ) <= barHeight ) {
setOpen( !isOpen( ) );
} else if ( isOpen ) {
double n = Math.floor( ( getPointer( ).y( ) - barHeight ) / itemHeight );
// n += itemRange; /* UP */
int index = ( int ) n + itemIndexOffset;
updateIndex( index );
}
}
}
private void updateIndex( int theIndex ) {
if ( theIndex >= items.size( ) ) {
return;
}
Map m = items.get( theIndex );
switch ( _myType ) {
case ( LIST ):
super.setValue( theIndex );
for ( Object o : items ) {
( ( Map ) o ).put( "state" , false );
}
m.put( "state" , !ControlP5.b( m.get( "state" ) ) );
break;
case ( DROPDOWN ):
super.setValue( theIndex );
setOpen( false );
getCaptionLabel( ).setText( ( m.get( "text" ).toString( ) ) );
break;
case ( CHECKBOX ):
m.put( "state" , !ControlP5.b( m.get( "state" ) ) );
break;
}
}
public ScrollableList setValue( float theValue ) {
updateIndex( ( int ) ( theValue ) );
return this;
}
@Override protected void onDrag( ) {
scroll( getPointer( ).dy( ) );
}
@Override protected void onScroll( int theValue ) {
scroll( theValue );
}
private void scroll( int theValue ) {
if ( isOpen() ) {
itemIndexOffset += theValue;
itemIndexOffset = ( int ) ( Math.floor( Math.max( 0 , Math.min( itemIndexOffset , items.size( ) - itemRange ) ) ) );
itemHover = -2;
}
}
@Override protected void onLeave( ) {
itemHover = -1;
}
@Override protected void onEnter( ) {
updateHover( );
}
@Override protected void onMove( ) {
updateHover( );
}
@Override protected void onEndDrag( ) {
updateHover( );
}
private void updateHover( ) {
if ( getPointer( ).y( ) > barHeight ) {
double n = Math.floor( ( getPointer( ).y( ) - barHeight ) / itemHeight );
itemHover = ( int ) ( itemIndexOffset + n );
} else {
itemHover = -1;
}
}
public void updateItemIndexOffset( ) {
int m1 = items.size( ) > itemRange ? ( itemIndexOffset + itemRange ) : items.size( );
int n = ( m1 - items.size( ) );
if ( n >= 0 ) {
itemIndexOffset -= n;
}
}
}