Fit MudCarousel resolution to image item content - css

I have the following template component for a dialog message to display a "full-screen" gallery of a few images (with varying resolutions).
<MudDialog Style="max-width: 95vw; max-height: 90vh;">
<DialogContent>
<MudCarousel Style="THIS SHOULD BE DYNAMIC" Class="mud-width-full" ShowArrows="#(ShowControls && Images.Count > 1)" ShowBullets=false TData="object">
#foreach (var image in Images)
{
<MudCarouselItem>
<MudImage Src="#("data:image/png;base64," + image)" Style="max-height: 80vh;" ObjectFit="ObjectFit.Contain" Elevation="5" Fluid />
</MudCarouselItem>
}
</MudCarousel>
</DialogContent>
</MudDialog>
Images is a Base64 List<string> parameter. The problem here is that I can't properly resize both the dialog and carousel containers to fit the images resolution without specifying fixed Width and Height properties in the Style parameter of the carousel component. Using 100% for either doesn't work as expected and the content size is ignored ending up with a 0x0 div.
I'm not sure if this is a CSS/MudBlazor issue or perhaps just wrong implementation on my part but I hope I explained the problem clearly enough.
Edit: Following the static logic and having access to an Image model containing resolution properties, this is what I'm trying now. It works but has some caveats, one being that images larger than 95vw or 90vh (max dialog size) will incorrectly expand the dialog in that axis and shrink down because of the object-fit attribute, so the problem is that the resizing values are set to the natural size and not the rendered size, some images might scaled down.
I mean, is this the best approach? This code makes me want to take a bath after touching it...
#inject ImageService ImageService
<div>
<MudDialog Style="max-width: 95vw; max-height: 90vh;">
<DialogContent>
<MudCarousel Class="mud-width-full" Style=#($"width: {_width}px; height: {_height}px;") ShowArrows="#(Images.Count > 1)" ShowBullets=false TData="object" AutoCycle=false>
#foreach (var image in Images)
{
<MudCarouselItem Style=#($"width: {image.Width}px; height: {image.Height}px; max-width: 85vw; max-height: 80vh; margin: 1rem 0;") Transition="Transition.Fade">
<MudImage Src="#("data:image/png;base64," + LoadCardImage(image.Path))" Style="width: 100%; height: 100%;" ObjectFit="ObjectFit.Contain" Elevation="0" Fluid />
</MudCarouselItem>
}
</MudCarousel>
</DialogContent>
</MudDialog>
</div>
#code {
[CascadingParameter]
public MudDialogInstance MudDialog { get; set; }
[Parameter]
public List<Image> Images { get; set; }
private int _width;
private int _height;
protected override void OnInitialized()
{
ResizeCarousel();
}
private void ResizeCarousel()
{
if (Images == null || Images.Count == 0) return;
if(Images.Count == 1)
{
_width = Images[0].Width;
_height = Images[0].Height;
}
else
{
_width = Images.Max(i => i.Width);
_height = Images.Max(i => i.Height);
}
}
private string LoadCardImage(string path) => ImageService.LoadImage(path);
}

Related

How to set TableColumn to the width it needs? [duplicate]

afaik The TableView in javafx have 2 column resize policies: CONSTRAINED_RESIZE_POLICY and UNCONSTRAINED_RESIZE_POLICY, but I want columns is resized to fit the content of theirs cells
I think it's a simple problem in other platform (like datagridview in C#) but can not resolve
After 3 years I come back to this problem again, some suggestions are calculating the size of text of data in each cell (it's complicated depending on font size, font family, padding...)
But I realize that when I click on the divider on table header, it's resized fit to content as I want. So I dig into JavaFX source code I finally found resizeColumnToFitContent method in TableViewSkin, but it is protected method, we can resolve by reflection:
import com.sun.javafx.scene.control.skin.TableViewSkin;
import javafx.scene.control.Skin;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
public class GUIUtils {
private static Method columnToFitMethod;
static {
try {
columnToFitMethod = TableViewSkin.class.getDeclaredMethod("resizeColumnToFitContent", TableColumn.class, int.class);
columnToFitMethod.setAccessible(true);
} catch (NoSuchMethodException e) {
e.printStackTrace();
}
}
public static void autoFitTable(TableView tableView) {
tableView.getItems().addListener(new ListChangeListener<Object>() {
#Override
public void onChanged(Change<?> c) {
for (Object column : tableView.getColumns()) {
try {
columnToFitMethod.invoke(tableView.getSkin(), column, -1);
} catch (IllegalAccessException | InvocationTargetException e) {
e.printStackTrace();
}
}
}
});
}
}
Note that we call "tableView.getItems()" so we have to call this function after setItems()
After testing the previous solutions I finally found one that worked for me.
So here is mine (call the method after inserting the data into table):
public static void autoResizeColumns( TableView<?> table )
{
//Set the right policy
table.setColumnResizePolicy( TableView.UNCONSTRAINED_RESIZE_POLICY);
table.getColumns().stream().forEach( (column) ->
{
//Minimal width = columnheader
Text t = new Text( column.getText() );
double max = t.getLayoutBounds().getWidth();
for ( int i = 0; i < table.getItems().size(); i++ )
{
//cell must not be empty
if ( column.getCellData( i ) != null )
{
t = new Text( column.getCellData( i ).toString() );
double calcwidth = t.getLayoutBounds().getWidth();
//remember new max-width
if ( calcwidth > max )
{
max = calcwidth;
}
}
}
//set the new max-widht with some extra space
column.setPrefWidth( max + 10.0d );
} );
}
I think just by overriding a call back function that returns true will solve your problem it will disable the re-sizing of columns and all columns will be re-sized to fit the content of their cells.
Example:
TableView<String[]> table = new TableView<>();
table.setColumnResizePolicy(new Callback<TableView.ResizeFeatures, Boolean>() {
#Override
public Boolean call(ResizeFeatures p) {
return true;
}
});
If you want that only one column fills the remaining width of a table, I have found a pretty straight forward solution, which is short and does not require the hacky reflection solution described above:
DoubleBinding usedWidth = columnA.widthProperty().add(columnB.widthProperty()).add(columnC.widthProperty());
fillingColumn.prefWidthProperty().bind(tableView.widthProperty().subtract(usedWidth));
Or to make it short:
// automatically adjust width of columns depending on their content
configAttributeTreeTable.setColumnResizePolicy((param) -> true );
I have used the other solutions on this question, and it works pretty good. However, the downside of this is when the width of the TableView is greater than the required width of the TableColumns together. I have created a hack to solve this problem, and it works OK:
orderOverview.setColumnResizePolicy((param) -> true );
Platform.runLater(() -> FXUtils.customResize(orderOverview));
where FXUtils.customResize() is created as follows:
public static void customResize(TableView<?> view) {
AtomicDouble width = new AtomicDouble();
view.getColumns().forEach(col -> {
width.addAndGet(col.getWidth());
});
double tableWidth = view.getWidth();
if (tableWidth > width.get()) {
TableColumn<?, ?> col = view.getColumns().get(view.getColumns().size()-1);
col.setPrefWidth(col.getWidth()+(tableWidth-width.get()));
}
}
I hope this could be helpful for other people as well!
This is the way I found :
tableview.setColumnResizePolicy( TableView.CONSTRAINED_RESIZE_POLICY );
idCol.setMaxWidth( 1f * Integer.MAX_VALUE * 50 ); // 50% width
nameCol.setMaxWidth( 1f * Integer.MAX_VALUE * 30 ); // 30% width
ageCol.setMaxWidth( 1f * Integer.MAX_VALUE * 20 ); // 20% width
This code autoresizes all column widths in relational proportions to the table width,
while it can fix the first column width to a given value when table width is lower than x
// To generalize the columns width proportions in relation to the table width,
// you do not need to put pixel related values, you can use small float numbers if you wish,
// because it's the relative proportion of each columns width what matters here:
final float[] widths = { 1.2f, 2f, 0.8f };// define the relational width of each column
// whether the first column should be fixed
final boolean fixFirstColumm = true;
// fix the first column width when table width is lower than:
final float fixOnTableWidth = 360; //pixels
// calulates sum of widths
float sum = 0;
for (double i : widths) {
sum += i;
}
// calculates the fraction of the first column proportion in relation to the sum of all column proportions
float firstColumnProportion = widths[0] / sum;
// calculate the fitting fix width for the first column, you can change it by your needs, but it jumps to this width
final float firstColumnFixSize = fixOnTableWidth * firstColumnProportion;
// set the width to the columns
for (int i = 0; i < widths.length; i++) {
table.getColumns().get(i).prefWidthProperty().bind(table.widthProperty().multiply((widths[i] / sum)));
// ---------The exact width-------------^-------------^
if (fixFirstColumm)
if (i == 0) {
table.widthProperty().addListener(new ChangeListener<Number>() {
#Override
public void changed(ObservableValue<? extends Number> arg0, Number oldTableWidth, Number newTableWidth) {
if (newTableWidth.intValue() <= fixOnTableWidth) {
// before you can set new value to column width property, need to unbind the autoresize binding
table.getColumns().get(0).prefWidthProperty().unbind();
table.getColumns().get(0).prefWidthProperty().setValue(firstColumnFixSize);
} else if (!table.getColumns().get(0).prefWidthProperty().isBound()) {
// than readd the autoresize binding if condition table.width > x
table.getColumns().get(0).prefWidthProperty()
.bind(table.widthProperty().multiply(firstColumnProportion));
}
}
});
}
}
advice to put the code in an separated TableAutoresizeModel class, there you can handle further calculations, for example on hiding columns add listener...
#HarleyDavidson 's answer in kotlin
val String.fxWidth: Double
get() = Text(this).layoutBounds.width
// call the method after inserting the data into table
fun <T> TableView<T>.autoResizeColumns() {
columnResizePolicy = TableView.UNCONSTRAINED_RESIZE_POLICY
columns.forEach { column ->
column.setPrefWidth(
(((0 until items.size).mapNotNull {
column.getCellData(it)
}.map {
it.toString().fxWidth
}.toMutableList() + listOf(
column.text.fxWidth
)).maxOrNull() ?: 0.0) + 10.0
)
}
}
This will set the minimum width of columns based on the font and the text, so that the column names wont be cropped.
public static void setDataTableMinColumnWidth(TableView<?> dataTable)
{
for (Node columnHeader : dataTable.lookupAll(".column-header"))
{
var columnString = columnHeader.getId();
if (columnString != null)
{
for (Node columnHeaderLabel : columnHeader.lookupAll(".label"))
{
var tableColumn = dataTable.getColumns()
.stream()
.filter(x -> x.getId()
.equals(columnString))
.findFirst();
if (columnHeaderLabel instanceof Label && tableColumn.isPresent())
{
var label = (Label) columnHeaderLabel;
/* calc text width based on font */
var theText = new Text(label.getText());
theText.setFont(label.getFont());
var width = theText.getBoundsInLocal()
.getWidth();
/*
* add 10px because of paddings/margins for the button
*/
tableColumn.get()
.setMinWidth(width + 10);
}
}
}
}
}
How to use:
dataTable.needsLayoutProperty()
.addListener((obs, o, n) -> setDataTableMinColumnWidth(dataTable));
For the Columns, the id property needs to be set first:
TableColumn<BundImportTask, String> columnTask = new TableColumn<>("My Column");
columnTask.setId("MyColumnId");
columnTask.setCellValueFactory(data -> new SimpleStringProperty(data.getValue()
.fileName()));
I implemented a solution that it's fairly more complicated than the ones that I found here, but that allows a specific column to be resized by double clicking on the header, while still letting the user resize columns manually.
This is achieved by listening to click events on the header of the table (TableHeaderRow). When a double click occurs, the specific column header is found by matching the mouse event X and Y.
Note: to make this work it's necessary that each column has an ID set.
// when skin is loaded (hence css), setup click listener on header to make column fit to content max width on double click
tableView.skinProperty().addListener((a, b, newSkin) -> {
TableHeaderRow headerRow = (TableHeaderRow) tableView.lookup("TableHeaderRow");
NestedTableColumnHeader headers = (NestedTableColumnHeader) (headerRow.getChildren().get(1));
headerRow.setOnMouseClicked(evt -> {
if (evt.getClickCount() != 2 || evt.getButton() != MouseButton.PRIMARY) return;
// find the header column that contains the click
for (TableColumnHeader header : headers.getColumnHeaders()) {
if (header.contains(header.parentToLocal(evt.getX(), evt.getY()))) {
fitColumnWidthToContent(header.getId());
}
}
evt.consume();
});
});
The method that takes care of the resizing is the following:
private void fitColumnWidthToContent (String colId) {
// find column matching id
TableColumn column = null;
for (TableColumn tempCol : tableView.getColumns()) {
if (tempCol.getId().equals(colId)) {
column = tempCol;
break;
}
}
if (column == null) {
throw new IllegalStateException("Column ID doesn't match any actual column");
}
// set default width to column header width
Text text = new Text(column.getText());
double max = text.getLayoutBounds().getWidth();
for (int i = 0; i < tableView.getItems().size(); i++ ) {
if (column.getCellData(i) == null) continue;
text = new Text(column.getCellData(i).toString());
double textWidth = text.getLayoutBounds().getWidth();
if (textWidth > max) {
max = textWidth;
}
}
column.setPrefWidth(max + 12);
}
I hope this can be useful to anyone.
In order to allow also manual resizing, it's necessary to add a bit more code on table initalization:
// listen to width changes in columns and set to pref width (otherwise if for example width changes because of
// user resizing the column, applying the old pref width won't work because it stayed the same)
for (TableColumn col : tableView.getColumns()) {
col.widthProperty().addListener((obs, oldVal, newVal) -> {
col.setPrefWidth(newVal.doubleValue());
});
}
I have implemented a solution for TreeTableView. It is still in evolution but it manifests now promising results. Hereafter a description of the solution.
In the control skin class, I added to the control children the TreeTableView and an invisible VBox. A cell factory provide derived cells to the target TreeTableColumn. The derived cells wrap a Label node which is added or removed to the invisible VBox according to the empty property, and which its prefWidth is set according to the cell width. The cells make use of:
getProperties().put(Properties.DEFER_TO_PARENT_PREF_WIDTH, Boolean.TRUE)
I override the cell's computePrefWidth() method as follow:
#Override
protected double computePrefWidth(double height) {
return Double.max(_box.prefWidth(-1.0), super.computePrefWidth(height) + 24.0);
}
The Vbox width property is bind to the TreeTableColumn's prefWidth. This is required to resize as well the header of the column.
Is worth to note, that at the time being, to simplify the development of a solution, this approach works well with built in sort, order, and resize feature disabled. Ie.
_nameColumn = new TreeTableColumn<>("Name");
_nameColumn.setResizable(false);
_nameColumn.setReorderable(false);
_nameColumn.setSortable(false);
Happy coding
After long research. Best Solution is..
tblPlan.setColumnResizePolicy((param) -> true );
Platform.runLater(() -> customResize(tblPlan));
"Custom Resize"
public void customResize(TableView<?> view) {
AtomicLong width = new AtomicLong();
view.getColumns().forEach(col -> {
width.addAndGet((long) col.getWidth());
});
double tableWidth = view.getWidth();
if (tableWidth > width.get()) {
view.getColumns().forEach(col -> {
col.setPrefWidth(col.getWidth()+((tableWidth-width.get())/view.getColumns().size()));
});
}
}
<TableView fx:id="datalist" layoutX="30.0" layoutY="65.0" prefHeight="400.0" AnchorPane.bottomAnchor="100.0" AnchorPane.leftAnchor="30.0" AnchorPane.rightAnchor="30.0" AnchorPane.topAnchor="100.0">
<columns>
<TableColumn fx:id="number" minWidth="-1.0" prefWidth="-1.0" style="width: auto;" text="number" />
<TableColumn fx:id="id" minWidth="-1.0" prefWidth="-1.0" text="id" />
<TableColumn fx:id="name" minWidth="-1.0" prefWidth="-1.0" text="name" />
<TableColumn fx:id="action" minWidth="-1.0" prefWidth="-1.0" text="todo" />
</columns>
**<columnResizePolicy>
<TableView fx:constant="CONSTRAINED_RESIZE_POLICY" />
</columnResizePolicy>**
</TableView>

CellTable Column Alignment to Right/Center

I need the Cell Table Column Alignment to be on Right/Center.Is it Possible to do using any GWT CellTable API Method? How to Achieve this?Any suggestion
Here is a good answer how to add a style name to a cell.
Dynamic styles for GWT cellTable cells
A solution can look like this:
t.addColumn(new TextColumn<String>()
{
#Override
public String getValue(String object)
{
return object;
}
#Override
public String getCellStyleNames(Context context, String object)
{
return super.getCellStyleNames(context, object) + " right";
}
});
in your css class add:
.right{
text-align: right;
}

How to add the css properties to an image in ImageResourceCell of CellTable

I created a CellTable with image column in GWT. Image is added through `ImageResource .
private Column<DocList, ImageResource> statusColumn;
private final Resources resources = GWT.create(Resources.class);
final String STATUS_COLUMN = "Status";
statusColumn = buildStatusColumn();
private Column<DocList, ImageResource> buildStatusColumn() {
statusColumn = new Column<DocList, ImageResource>(
new ImageResourceCell()) {
#Override
public ImageResource getValue(DocList object) {
return resources.draft();
}
};
statusColumn.setDataStoreName(STATUS_COLUMN);
return statusColumn;
}
public interface Resources extends ClientBundle {
#Source("draft.png")
ImageResource draft();
}
But the problem is that I want to change some css properties of the image, for example, size or cursor="pointer" for click event, but I don't know how. In Firebug there is a default size.
How to add css to image done by ImageResource in GWT?
Column has a method called getCellStyleName().
You can override this method and return a style that reflects the image you use
#Override
public String getCellStyleName()
{
return resources.draft().getName();
}
Then you could create a style in your sheet like this:
.draft img {
cursor: pointer;
width: ...;
height: ...;
}

How to set up PlayN size

I've tried :
graphics().setSize(800, 600);
But it has no effects (at least with java and html).
And it seems this method is deprecated. What is the best way to set up the game size ?
This method was deprecated in version 1.5 of PlayN, the size of your game view on Android/iOS is dictated by the device. The size on Java is configured via JavaPlatform.Config. The size in HTML is configured by the size of your playn-root div.
For example on the java backend:
public class GameJava {
public static void main(String[] args) {
//Setting the size of the Java Backend
Config config = new Config();
config.width = 800;
config.height = 480;
JavaPlatform platform = JavaPlatform.register(config);
platform.assets().setPathPrefix("your/package/resources");
PlayN.run(new Game());
}
}
for HTML do something like this:
<style>
#playn-root {
width: 640px;
height: 480px;
}
</style>
....
<div id="playn-root"></div>
<body>
<script src="game/game.nocache.js"></script>
</body>

GWT date picker scroll issue

I am using GWT datepicker in my web page .When i am adding in the bottem of the page its
behaviour is quite abnormal as shown in the snap shot .
I tried with z-index and with some known css properties .But i did'nt cameout from the digg.
Any other css or date picker properties will resolve this ??
I got the solution for this
dateIcon.addClickHandler(new ClickHandler()
{
#Override
public void onClick(ClickEvent event)
{
int left = dateIcon.getAbsoluteLeft() + 30;
int top = dateIcon.getAbsoluteTop() + 10;
if(dateIcon.getAbsoluteTop()+400>Window.getClientHeight()){
top = dateIcon.getAbsoluteTop()-200;
}
popUp.setPopupPosition(left, top);
if (isControlEnabled())
![enter image description here][2] {
popUp.show();
} else
{
popUp.hide();
}
}
});

Resources