Я пишу для университетского проекта программное обеспечение на java - javafx, но у меня есть некоторые проблемы с графической реализацией функции голосования.
У меня есть такая иконка политической партии:
Я хочу в java поставить букву X над этим значком, чтобы получить что-то вроде этого:
Моим решением может быть возможность нарисовать одну линию и другую линию над изображением, но я не знаю, как это сделать.
package unimi.sysvotes.elettore;
import java.io.File;
import java.io.IOException;
import javafx.fxml.FXML;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.Pane;
public class VotoController {
@FXML Pane listaUnoCandidatoUninominale;
@FXML ImageView listaUnoSimboloUno;
@FXML
private void initialize() {
File fileUno = new File("C:\\Users\\Administrator\\Desktop\\progettazione\\simboli\\popoloDellaLiberta.jpg");
Image imageUno = new Image("file:///"+fileUno.getAbsolutePath());
listaUnoSimboloUno.setImage(imageUno);
}
@FXML
private void listaUnoSimboloUnoAction(MouseEvent me) throws IOException {
System.out.println("Votato");
/*
How put Two line above ImageView popolo?
*/
Line lineOne = new Line(10, 10, 80, 80);
lineOne.setFill(null);
lineOne.setStroke(Color.BLACK);
lineOne.setStrokeWidth(2);
Line lineTwo = new Line(80, 10, 10, 80);
lineTwo.setFill(null);
lineTwo.setStroke(Color.BLACK);
lineTwo.setStrokeWidth(2);
}
}
@kleopatra, я редактирую вопрос. Теперь это версия контроллера javafx.




Я использовал StackPane.
Я помещаю холст и ImageView в стек, а затем рисую линию на холсте. Я также меняю порядок узлов в панели стека.
public class VotoController {
@FXML Pane listaUnoCandidatoUninominale;
@FXML StackPane listaUnoSimboloUnoStack;
@FXML ImageView listaUnoSimboloUno;
@FXML Canvas listaUnoSimboloUnoX;
@FXML
private void initialize() {
File fileUno = new File("C:\\Users\\Administrator\\Desktop\\progettazione\\simboli\\popoloDellaLiberta.jpg");
Image imageUno = new Image("file:///"+fileUno.getAbsolutePath());
listaUnoSimboloUno.setImage(imageUno);
}
@FXML
private void votoCandidatoUninominalAction(MouseEvent me) throws IOException {
System.out.println("Votato");
listaUnoCandidatoUninominale.setStyle("-fx-background-image: url('file:C:/Users/Administrator/Desktop/progettazione/voto/backgroundcandidatouninominale.jpg');");
}
@FXML
private void listaUnoSimboloUnoAction(MouseEvent me) throws IOException {
System.out.println("Votato");
GraphicsContext gc = listaUnoSimboloUnoX.getGraphicsContext2D();
Line lineOne = new Line(10, 10, 40, 40);
lineOne.setFill(null);
lineOne.setStroke(Color.BLACK);
lineOne.setStrokeWidth(2);
gc.beginPath();
gc.setLineWidth(5);
gc.moveTo(0, 0);
gc.lineTo(0, 0);
gc.lineTo(50, 50);
gc.stroke();
gc.beginPath();
gc.setLineWidth(5);
gc.moveTo(50, 0);
gc.lineTo(50, 0);
gc.lineTo(0, 50);
gc.stroke();
ObservableList<Node> childs = listaUnoSimboloUnoStack.getChildren();
if (childs.size() > 1) {
//
Node topNode = childs.get(childs.size()-1);
topNode.toBack();
}
}
}
Вот альтернативное решение, основанное на Pane.
Панель используется, а не группа, поэтому панель можно стилизовать с помощью CSS. Если в этом нет необходимости, вместо этого можно использовать группу.
Слои выполняются неявно с помощью алгоритм художника, который JavaFX использует для рендеринга. Этот алгоритм рисует элементы, добавленные позже в списке, поверх элементов, добавленных ранее в списке.
Решение реализует возможность выбора и отмены выбора изображений, что на самом деле не было задано в вопросе, но, похоже, подразумевается в тексте вашего вопроса.
Понятие выбираемого изображения похоже на ToggleButton или CheckBox. Таким образом, вместо этого можно использовать ToggleButton и при необходимости стилизовать его с помощью CSS. Например, X можно получить с помощью фонового слоя svgpath в CSS, именно так работают встроенные элементы управления, такие как переключатель. Однако я не применил этот подход здесь (он немного сложнее, чем то, что я представляю).
Пример расширяется из Pane, но при желании вы можете использовать агрегацию, а не расширение.
Используемые изображения предоставлены в ответе на этот вопрос:
X добавляется к дочерним элементам панели поверх изображения с помощью следующего кода.
public SelectableImageView(Image image) {
imageView = new ImageView(image);
getChildren().add(imageView);
selectionMark = createSelectionMark();
// ... additional listener and initialization code here.
}
private Node[] createSelectionMark() {
double w = imageView.getImage().getWidth();
double h = imageView.getImage().getHeight();
Line l1 = new Line(INSET, INSET, w - INSET, h - INSET);
l1.setStrokeWidth(INSET * .75);
l1.setStrokeLineCap(StrokeLineCap.ROUND);
Line l2 = new Line(INSET, h - INSET, w - INSET, INSET);
l2.setStrokeWidth(INSET * .75);
l2.setStrokeLineCap(StrokeLineCap.ROUND);
return new Node[] { l1, l2 };
}
private void addSelection() {
getChildren().addAll(selectionMark);
}
Исполняемый пример
import javafx.application.Application;
import javafx.beans.property.*;
import javafx.geometry.Insets;
import javafx.scene.*;
import javafx.scene.image.*;
import javafx.scene.layout.*;
import javafx.scene.shape.*;
import javafx.stage.Stage;
import java.util.*;
import java.util.stream.Collectors;
public class SelectableImagesApp extends Application {
private static final double PADDING = 20;
@Override
public void start(Stage stage) throws Exception {
TilePane imageTiles = new TilePane(PADDING, PADDING);
imageTiles.setPadding(
new Insets(PADDING)
);
imageTiles.getChildren().addAll(
createSelectableImages()
);
imageTiles.setPrefColumns(ImageNames.values().length);
stage.setScene(new Scene(imageTiles));
stage.show();
}
public enum ImageNames {
Medusa,
Dragon,
Treant,
Unicorn
}
private List<SelectableImageView> createSelectableImages() {
return Arrays.stream(ImageNames.values())
.map(m ->
new SelectableImageView(
new Image(
Objects.requireNonNull(
SelectableImagesApp.class.getResource(
m + "-icon.png"
)
).toExternalForm()
)
)
).collect(Collectors.toList());
}
public static void main(String[] args) {
launch(args);
}
}
class SelectableImageView extends Pane {
private final ImageView imageView;
private final Node[] selectionMark;
private BooleanProperty selected = new SimpleBooleanProperty(false);
private final double INSET = 10;
public SelectableImageView(Image image) {
imageView = new ImageView(image);
getChildren().add(imageView);
selectionMark = createSelectionMark();
selected.addListener((observable, wasSelected, isSelected) -> {
if (isSelected) {
addSelection();
} else {
removeSelection();
}
});
this.setStyle("-fx-background-color: lightblue;");
this.setPickOnBounds(true);
this.setOnMouseClicked(e -> {
selected.set(!selected.get());
});
}
private Node[] createSelectionMark() {
double w = imageView.getImage().getWidth();
double h = imageView.getImage().getHeight();
Line l1 = new Line(INSET, INSET, w - INSET, h - INSET);
l1.setStrokeWidth(INSET * .75);
l1.setStrokeLineCap(StrokeLineCap.ROUND);
Line l2 = new Line(INSET, h - INSET, w - INSET, INSET);
l2.setStrokeWidth(INSET * .75);
l2.setStrokeLineCap(StrokeLineCap.ROUND);
return new Node[] { l1, l2 };
}
private void addSelection() {
getChildren().addAll(selectionMark);
}
private void removeSelection() {
getChildren().removeAll(selectionMark);
}
public boolean isSelected() {
return selected.get();
}
public BooleanProperty selectedProperty() {
return selected;
}
public void setSelected(boolean selected) {
this.selected.set(selected);
}
}