layout - जावा एफएक्स में स्वचालित रूप से टाइलें खींचने के साथ टाइलपैन




javafx gridpane (2)

क्या टाइलपेन या फ्लोपेन और ग्रिडपैन दोनों से सर्वश्रेष्ठ करने के लिए जावाएफएक्स में कोई रास्ता है?
यहां मैं क्या हासिल करना चाहता हूं:

सबसे पहले, मुझे ग्रिडपैन के विचार पसंद है, जहां मैं एक एम एक्स एन ग्रिड स्थापित कर सकता हूं जो स्वचालित रूप से अपने माता-पिता के कंटेनर के भीतर फिर से एम स्तंभ और एन पंक्तियों में समान रूप से बांटते हैं। तब मैं कुछ बच्चे तत्व डाल सकता हूं जो पूरी तरह से प्रत्येक सेल को भरते हैं, और वे ग्रिड के साथ आगे बढ़ेंगे। यह अच्छा है।
लेकिन एक खामी है: मुझे स्पष्ट रूप से यह निर्दिष्ट करना होगा कि प्रत्येक नियंत्रण कब जाना चाहिए, इसकी पंक्ति और स्तंभ संख्या सेट करके

फिर, ऐसे फ़्लोपेन या टाइलपैन जैसे लेआउट कंटेनर होते हैं, जो कि अपने मूल तत्वों को स्वचालित रूप से रिफ्लो करते हैं, जब पेरेंट कन्टेनर इसका आकार बदलता है। जब मैं एक और बच्चे तत्व जोड़ता हूं, तो यह सूची के अंत में स्वतः संलग्न होता है, और तत्वों की सूची कंटेनर के किनारे पर पहुंचने के बाद स्वचालित रूप से लपेटता है, जब वहाँ एक और तत्व फिट करने के लिए बहुत कम जगह होती है।
लेकिन यहां एक दोष भी है: बच्चे के तत्वों में केवल कठोर, पूर्व-परिभाषित आकार हो सकते हैं। वे अपने मूल तत्व के साथ नहीं फैल जाएगा

और यहाँ मुझे क्या चाहिए:
मुझे इन दोनों कंटेनरों से सर्वश्रेष्ठ की जरूरत है, अर्थात, मुझे एन ग्रिड (चलो 4 × 4) से एम चाहिए, जहां प्रत्येक सेल माता-पिता / माउंट द्वारा माता-पिता / एम और खिड़की के साथ फैला हुआ है, ताकि यह हमेशा से हो 4 × 4 कोशिकाएं, लेकिन उनके आकार (उनकी सामग्री के आकार के साथ) तदनुसार फैले हुए हैं। लेकिन मैं कंटेनर को स्पष्ट रूप से नहीं बताता कि इसमें कौन से पंक्ति और स्तंभ हर नए बच्चे को जोड़ता है, मैं वहां जोड़ता हूं। इसके बजाय, मैं इसे जोड़ना चाहता हूं और कंटेनर को पहले खाली सेल को डालने के लिए इसे डालने के लिए, दाएं से दायें कोशिकाओं को भरना, फिर ऊपर से नीचे तक अगर मौजूदा पंक्ति में कोई खाली कक्ष नहीं छोड़ा जाए

क्या इनमें से किसी भी पूर्वनिर्धारित कंटेनर के गुणों के लिए कुछ जादुई सेटअप है जो मुझे यह प्राप्त करने की अनुमति देगा? या मुझे इस तरह के कंटेनर को लिखने की आवश्यकता है?


आपके द्वारा ButtonGridPane गए प्रयोजन के लिए, मैंने ButtonGridPane बनाया है यह एक पहला मसौदा है, और अभी भी सुधार के लिए कमरा है, लेकिन शायद यह आपको एक बुनियादी विचार दे सकता है।

public class ButtonGrid extends Pane {

    private static final double DEFAULT_RATIO = 0.618033987;

    private int                 columnCount;
    private double              ratio;

    public ButtonGrid(int columnCount) {
        this(columnCount, DEFAULT_RATIO);
    }

    public ButtonGrid(int columnCount, double heightToWidthRatio) {
        getStyleClass().add("button-grid");
        this.columnCount = columnCount;
        ratio = heightToWidthRatio;
    }

    public void setColumnCount(int columnCount) {
        this.columnCount = columnCount;
    }

    public void setHeightToWidthRatio(double ratio) {
        this.ratio = ratio;
    }

    @Override
    public Orientation getContentBias() {
        return Orientation.HORIZONTAL;
    }

    @Override
    protected void layoutChildren() {
        double left = getInsets().getLeft();
        double top = getInsets().getTop();

        double tileWidth = calculateTileWidth(getWidth());
        double tileHeight = calculateTileHeight(getWidth());

        ObservableList<Node> children = getChildren();
        double currentX = left;
        double currentY = top;
        for (int idx = 0; idx < children.size(); idx++) {
            if (idx > 0 && idx % columnCount == 0) {
                currentX = left;
                currentY = currentY + tileHeight;
            }
            children.get(idx).resize(tileWidth, tileHeight);
            children.get(idx).relocate(currentX, currentY);
            currentX = currentX + tileWidth;
        }
    }

    @Override
    protected double computePrefWidth(double height) {
        double w = 0;
        for (int idx = 0; idx < columnCount; idx++) {
            Node node = getChildren().get(idx);
            w += node.prefWidth(-1);
        }
        return getInsets().getLeft() + w + getInsets().getRight();
    }

    @Override
    protected double computePrefHeight(double width) {
        double h = calculateTileHeight(width) * getRowCount();
        return getInsets().getTop() + h + getInsets().getBottom();
    }

    private double calculateTileHeight(double width) {
        return calculateTileWidth(width) * ratio;
    }

    private double calculateTileWidth(double width) {
        return (-getInsets().getLeft() + width - getInsets().getRight()) / columnCount;
    }

    private int getRowCount() {
        return getChildren().size() / columnCount;
    }
}

ठीक है, समाधान पर मेरा अपना प्रयास है:

चूंकि GridPane लगभग पूरी तरह से मेरी जरूरत के मुताबिक काम करता है, इसलिए मैं अपनी सामग्री को स्वचालित रूप से GridPane नहीं करता, मैंने GridPane उप-वर्ग का निर्णय लिया और अपने बच्चे के नियंत्रण को स्वचालित रूप से बहने के लिए कस्टम कोड जोड़ दिया। (संकेत के लिए jns के लिए धन्यवाद कि जावाएफएक्स पुस्तकालय नियंत्रण वर्गों को उप-वर्ग किया जा सकता है।)

इसलिए मैंने ग्रिडपेन को उप-वर्ग दिया और बच्चों की अपनी आंतरिक सूची के लिए श्रोता को जोड़ा, ताकि जब भी कोई बच्चा जोड़ा जाए या उस सूची से हटा दिया जाए, या सूची किसी तरह बदल जाती है (जैसे हम बच्चों को पुन: क्रमित करते हैं), एक निजी विधि को कहा जाता है ग्रिड में बच्चों को सूची में उनकी स्थिति के अनुसार कॉलम और पंक्तियों को सही करने के लिए निर्दिष्ट करके उन्हें फिर से भरें। मैंने सूची में पोजीशन को पंक्ति और कॉलम नंबरों में परिवर्तित करने और वापस करने के लिए दो निजी हेल्पर फ़ंक्शन भी जोड़े।

मुझे पता है कि यह सही और सुरुचिपूर्ण नहीं है, लेकिन हे, यह काम करता है, और यह मेरी ज़रूरतों के लिए अच्छी तरह से काम करता है: पी तो मैं यहां कोड प्रकाशित करता हूं अगर किसी और की समस्या एक समान होती है:

package flowgrid;

import javafx.collections.ObservableList;
import javafx.collections.ListChangeListener;

import javafx.scene.Node;
import javafx.scene.layout.GridPane;
import javafx.scene.layout.ColumnConstraints;
import javafx.scene.layout.RowConstraints;
import javafx.scene.layout.Priority;
import javafx.geometry.HPos;
import javafx.geometry.VPos;

import javafx.beans.property.IntegerProperty;
import javafx.beans.property.SimpleIntegerProperty;
import javafx.beans.NamedArg;

/**
 * This class subclasses the GridPane layout class.
 * It manages its child nodes by arranging them in rows of equal number of tiles.
 * Their order in the grid corresponds to their indexes in the list of children
 * in the following fashion (similarly to how FlowPane works):
 * 
 *      +---+---+---+---+
 *      | 0 | 1 | 2 | 3 |
 *      +---+---+---+---+
 *      | 4 | 5 | 6 | 7 |
 *      +---+---+---+---+
 *      | 8 | 9 | … |   |
 *      +---+---+---+---+
 *  
 * It observes its internal list of children and it automatically reflows them
 * if the number of columns changes or if you add/remove some children from the list.
 * All the tiles of the grid are of the same size and stretch accordingly with the control.
 */
public class FlowGridPane extends GridPane
{
   // Properties for managing the number of rows & columns.
   private IntegerProperty rowsCount;
   private IntegerProperty colsCount;

   public final IntegerProperty colsCountProperty() { return colsCount; }
   public final Integer getColsCount() { return colsCountProperty().get(); }
   public final void setColsCount(final Integer cols) {
      // Recreate column constraints so that they will resize properly.
      ObservableList<ColumnConstraints> constraints = getColumnConstraints();
      constraints.clear();
      for (int i=0; i < cols; ++i) {
         ColumnConstraints c = new ColumnConstraints();
         c.setHalignment(HPos.CENTER);
         c.setHgrow(Priority.ALWAYS);
         c.setMinWidth(60);
         constraints.add(c);
      }
      colsCountProperty().set(cols);
      reflowAll();
   }

   public final IntegerProperty rowsCountProperty() { return rowsCount; }
   public final Integer getRowsCount() { return rowsCountProperty().get(); }
   public final void setRowsCount(final Integer rows) {
      // Recreate column constraints so that they will resize properly.
      ObservableList<RowConstraints> constraints = getRowConstraints();
      constraints.clear();
      for (int i=0; i < rows; ++i) {
         RowConstraints r = new RowConstraints();
         r.setValignment(VPos.CENTER);
         r.setVgrow(Priority.ALWAYS);
         r.setMinHeight(20);
         constraints.add(r);
      }
      rowsCountProperty().set(rows);
      reflowAll();
   }

   /// Constructor. Takes the number of columns and rows of the grid (can be changed later).
   public FlowGridPane(@NamedArg("cols")int cols, @NamedArg("rows")int rows) {
      super();
      colsCount = new SimpleIntegerProperty();  setColsCount(cols);
      rowsCount = new SimpleIntegerProperty();  setRowsCount(rows);
      getChildren().addListener(new ListChangeListener<Node>() {
         public void onChanged(ListChangeListener.Change<? extends Node> change) {
            reflowAll();
         }
      } );
   }

   // Helper functions for coordinate conversions.
   private int coordsToOffset(int col, int row) { return row*colsCount.get() + col; }
   private int offsetToCol(int offset) { return offset%colsCount.get(); }
   private int offsetToRow(int offset) { return offset/colsCount.get(); }

   private void reflowAll() {
      ObservableList<Node> children = getChildren();
      for (Node child : children ) {
         int offs = children.indexOf(child);
         GridPane.setConstraints(child, offsetToCol(offs), offsetToRow(offs) );
      }
   }
}

जैसा कि आप देख सकते हैं, मैंने गेटर्स और सेटर्स के साथ पंक्तियों और स्तंभों की संख्या के लिए गुण भी उपयोग किया है। जब कोई पंक्तियों या स्तंभों की संख्या बदलने के लिए एक सेटर का उपयोग करता है, तो ग्रिडपैन के अंदर कॉलम / पंक्ति की बाधाओं की आंतरिक सूचियां बनायी जा रही हैं ताकि वे सही तरीके से बदल सकें, और जब कॉलम की संख्या में परिवर्तन होता है तो सामग्री को रिफ्लो किया जा रहा है।

@NamedArg में @NamedArg भी हैं, ताकि एक एफएक्सएमएल फ़ाइल में वर्णित लेआउट से प्रारंभिक संख्या वाली पंक्तियों और स्तंभों के साथ यह नियंत्रण बना सके।

चूंकि यह बहुत ही मेरी समस्या को एक तरह से हल किया है, इसलिए मैं अपना जवाब स्वीकार कर रहा हूं। लेकिन अगर कोई बेहतर समाधान पोस्ट करेगा, तो मैं ख़ुशी से उसका जवाब स्वीकार कर दूंगा।

मुझे यह बताएं बेझिझक, अगर आपके पास इस कोड के सुधार के बारे में कोई सुझाव है, या यदि आप सोचते हैं कि कुछ और अधिक सुन्दरता से किया जा सकता है, क्योंकि - मैंने कहा - यह अभी तक बिल्कुल सही नहीं है।