简体   繁体   中英

How to cast a reference with an object's original class?

I'm working on a GUI library for Processing, and I have got a class Component . I have a bunch of other classes that extend Component : Label , Button (Which extends Label ), Panel and Icon . These classes continue just the "logic" part (position, text, function checking if they are clicked etc...).

The class Panel has inside of it an ArrayList of Component , and you can add to it buttons, labels etc...

To display the components I decided to use a class Theme , which has inside some overloadings of the function display(Component component) (one for Label , one for Button , one for Panel etc...).

Inside display(Panel panel) , at some point, I display all the children of the panel, but, instead of treating them (the children) as Button or Label , it treats all of them as Component . How can I solve this ISSUE?

  1. I've already tried to use a method display() inside the classes Component , Button etc... it works partly, but it gives some "coding problems": to override the function display you have to create a new class (Example: GreenBackgroundButton extends Button{}). Also, by putting all the function in an external class, you can control all the grapihcs of you Program with a single class, so you can have the same background for all the components with a single function displayBackground() etc...

  2. instanceof can't be used, because, if I have to use it to cast the children of the panel, the user can't create custom components, because they would be displayed as Component not as TextField (example).

  3. I've tried casting directly display((Button)panel.getChildren.get(0)) , but, as it Should, when I use a label, it gives an error (as expected).

  4. I've tried casting like this too: panel.getChildren().get(0).getClass().cast(panel.getChildren().get(0)) , and it doesn't work, I don't know why. (I tried all its variants, like creating an external object etc...)

  5. If you need more code, you can ask...

public void display(Panel panel) {
    println("panel");
    if (panel.isVisible()) {
      pushMatrix();
      translate(panel.getX(), panel.getY());
      displayBackground(panel, #AAAAAA);

      for (int i = 0; i < panel.getChildren().size(); i++) {
        this.display(panel.getChildren().get(i).getClass().cast(panel.getChildren().get(i))); //THIS IS THE LINE WITH THE ISSUE
        //println(panel.getChildren().get(i).getClass().cast(panel.getChildren().get(i)));
      }
      popMatrix();
    }
  }


Theme basicTheme;
Button close;
Panel panel;

void settings() {
  size(400, 600, P2D);
}

void setup() {
  basicTheme = new Theme();

  close = new Button();
  close.setBounds(10, 10, 100, 25);
  close.setText("close");

  panel = new Panel();
  panel.setBounds(50, 200, 200, 200);
  panel.add(close);
}

void draw() {
  background(255);

  basicTheme.display(panel);
}

I expect to see on the canvas a working button inside the panel, instead of seeing a component. I don't have any particular error I can think of right now.

Using instanceof is almost always a hack, and is probably a symptom of a bad design.

What you've described sounds exactly like an existing Java library called the Abstract Window Toolkit (AWT), so you might consider "borrowing" some of their design patterns.

  • Component is an abstract class that defines an abstract paint() function. The paint() function takes a Graphics argument. More on that in a second.
  • Button and Label extend Component and overide the paint() function.
  • Graphics is a class that contains functions like drawRect() and setBackground() . It encapsulates shared drawing code, similar to what I think your Theme class would do.

If I were you, I would consider taking a similar approach for your library.

I'll try to address some of your other comments:

Example: GreenBackgroundButton extends Button{}

Favor composition over inheritance for cases like this. You should not need to extend Button to set a background. Instead, have a setBackground() function in the Button() class (or in the Component class).

Also, by putting all the function in an external class, you can control all the rapihcs of you Program with a single class, so you can have the same background for all the components with a single function displayBackground() etc.

It sounds like this belongs in your Component class.

Also, taking a step back, I would encourage you to avoid the temptation to over-engineer a solution. You might think you need a complicated design with several levels of inheritance and many different classes, but chances are a simpler design will probably get you almost everything you need. Specifically, I don't see a huge benefit to extracting any code into the Theme class. I would probably put everything directly in my component subclasses like Button and Label .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM