I have a few columns in a tableview, and would like their widths to stay constant when the view expands. This seems quite simple with maxWidth = minWidth = 120.px. My problem is I would also like to completely disable the resizing of the columns by the user. This is what I have so far:
tableview(model) {
smartResize()
column("DATE", Model::date) {
isResizable = true // This is where it seems to work
style {
minWidth = 120.px
prefWidth = 120.px
}
cellFormat {
graphic = cache(rowItem.id) {
datepicker(rowItem.dateProperty) {
style {
textAlignment = TextAlignment.CENTER
maxWidth = 200.px
}
}
}
}
}
column("LAME/\nWCO", RWADetail::lameWco).makeEditable().style {
alignment = Pos.CENTER
}
column("DESCRIPTION", RWADetail::description).makeEditable().remainingWidth().style {
alignment = Pos.CENTER_LEFT
}
}
However this leads to strange result where the empty rows below have different widths.
This is a snip of the resulting date column with inconsistent sizing for the empty rows:
Am I on the right track?
Looks like I answered my own question: the trick was the TornadoFx method called fixedWidth(200). Below is my modified code
tableview(model) {
smartResize()
column("DATE", Model::date) {
style {
fixedWidth(120)
}
cellFormat {
graphic = cache(rowItem.id) {
datepicker(rowItem.dateProperty)
}
}
}
column("LAME/\nWCO", RWADetail::lameWco).makeEditable().style {
fixedWidth(120)
alignment = Pos.CENTER
}
column("DESCRIPTION", RWADetail::description).makeEditable().remainingWidth().style {
fixedWidth(120)
alignment = Pos.CENTER_LEFT
}
}
Related
I want to create a string with the max number of characters allowable in the box.
setContent {
ViewincomposetestTheme {
var size by remember { mutableStateOf(IntSize.Zero) }
var widthdp by remember { mutableStateOf(0.dp) }
BoxWithConstraints(Modifier.fillMaxSize().background(Color.Yellow)) {
val widthOfChar = 13 // how do I find this
var string by remember {
mutableStateOf(
StringBuffer()
.apply {
repeat(maxWidth.value.toInt() / widthOfChar) { append("H") }
}
.toString()
)
}
Text(string)
}
}
}
You can create a separate Text to calculate the size of a character, which will report you its size with onTextLayout. Using drawWithContent you can prevent it from being drawn.
Also in your example you get the width using maxWidth.value.toInt(): here you get the value of dp, not pixels. You could convert it using LocalDensity, but you also get the pixel value directly from BoxWithConstraints using constraints.maxWidth.
BoxWithConstraints(
Modifier
.fillMaxSize()
.background(Color.Yellow)
) {
var charWidth by remember { mutableStateOf<Int?>(null) }
val string = remember(maxWidth, charWidth) {
charWidth?.let { charWidth ->
StringBuffer()
.apply {
repeat(constraints.maxWidth / charWidth) { append("H") }
}
.toString()
}
}
Text(
"H",
onTextLayout = {
charWidth = it.size.width
},
modifier = Modifier.drawWithContent { }
)
string?.let {
Text(string)
}
}
You can just use the maxWidth parameter of the BoxWithConstraints, then convert the obtained dp value toPx(). Decide a textsize for the TextField in sp and then do whatever calculations you want to do after converting that to Px as well. Max characters will be maxWidth / textSize, roughly.
Im fairly new to Swift and I'm trying to produce a HStack (that will be used in a progress bar) of element and to be able to add elements with a button.
Im not sure if I should use a variable in the ForEach(1..<Variable) section or use another method. Here is the code I have so far but it did not work.
struct ContentView: View {
#State var fill : CGFloat = 0
#State var NumberOfCircles : Int = 0
var body: some View {
HStack(spacing:100) {
ForEach(0..<NumberOfCircles){ _ in
MyShape()
}
Button(action: {NumberOfCircles = 5}, label: {
Text("Button")
})
}
ForEach in SwiftUI needs a constant range to loop over. However,
as the error suggests, if you conform to Identifiable or use ForEach(_:id:content:) and provide an explicit id it is happy. So try this:
struct ContentView: View {
#State var fill: CGFloat = 0
#State var NumberOfCircles: Int = 0
var body: some View {
HStack(spacing: 20) {
ForEach(0..<NumberOfCircles, id: \.self){ _ in // <-- here
MyShape()
}
Button(action: {NumberOfCircles = 5}){
Text("Button")
}
}
}
}
I'm not sure what's your problem, but I tested this code and it works:
struct ContentView: View {
#State var numberOfCircles = 1
var body: some View {
VStack {
HStack {
ForEach(0..<numberOfCircles, id:\.self) { _ in
Circle()
.frame(width: 30, height: 30)
}
}
Button { numberOfCircles = 5 } label: {
Text("Add Circles")
}
}
}
}
Btw, naming convention for variables in Swift is camelCase. That means that declaring a variable you should name it numberOfCircles , not NumberOfCircles . The first uppercase letter is reserved for naming Classes, Structs and Protocols.
I'd like to implement a card style UI(as the screen shot), card is using a wxPanel as a container, a static text and a static bmp in the panel. the card will zoom in and color changed when mouse on it, when the mouse leave the card, size and color will recover as normal state. I add some logic in onEnter and onLeave of wxPanel to handle zoom and color change. the card works fine in most of cases, but if mouse move quickly, multiple cards will be selected. From output log, it seems the issue happens in OnLeave, !GetClientRect().Contains(event.GetPosition()) = false, even the mouse actually has been out of the rect of the card. how can the card work as expected even mouse move quickly?
enter image description here
void TypeCard::OnEnter(wxMouseEvent& event) {
wxRect rect = GetClientRect();
wxPoint pnt = event.GetPosition();
TRACELOG_WARNING("###### On Enter left=%d top=%d width=%d height=%d", rect.GetLeft(), rect.GetTop(), rect.GetWidth(), rect.GetHeight());
TRACELOG_WARNING("&&&&&& On Enter x=%d y=%d", pnt.x, pnt.y);
if (GetClientRect().Contains(event.GetPosition()) && !selected_ ) {
TRACELOG_WARNING("&&&&&&On Enter = true");
if (m_bZoomEnabled) {
ZoomCard(zoom_in, 5, 5);
}
selected_ = true;
} else {
TRACELOG_WARNING("*****************************************************On Enter = false selected_ = %d", (int)selected_ );
}
// have_focus_ = true;
Refresh(false);
Update();
event.Skip();
}
void TypeCard::OnLeave(wxMouseEvent& event) {
wxRect rect = GetClientRect();
wxPoint pnt = event.GetPosition();
TRACELOG_WARNING("###### On OnLeave left=%d top=%d width=%d height=%d", rect.GetLeft(), rect.GetTop(), rect.GetWidth(), rect.GetHeight());
TRACELOG_WARNING("&&&&&& On OnLeave x=%d y=%d", pnt.x, pnt.y);
// if (!GetClientRect().Contains(event.GetPosition())) {
if (!rect.Contains(pnt)) {
if (m_bZoomEnabled) {
ZoomCard(zoom_out, 5, 5);
}
selected_ = false;
} else {
TRACELOG_WARNING("*****************************************************On OnLeave = false");
}
if (!selected_) {
// have_focus_ = false;
Refresh(false);
Update();
}
event.Skip();
}
void TypeCard::OnPaint(wxPaintEvent& event) {
wxPaintDC dc(this);
wxColour colour = selected_ ? CARD_SELECT_BACKGROUND_COLOUR : COMPONENT_UNSELECT_BACKGROUND_COLOUR;
wxCursor cur = selected_ ? wxCURSOR_HAND : wxCURSOR_ARROW;
dc.SetPen(wxPen(colour));
dc.SetBrush(wxBrush(colour));
this->SetCursor(cur);
const wxWindowList& list = this->GetChildren();
for (wxWindowList::compatibility_iterator node = list.GetFirst(); node; node = node->GetNext()) {
wxWindow* current = node->GetData();
if (current) {
current->SetBackgroundColour(colour);
current->SetCursor(cur);
}
}
dc.DrawRectangle(0, 0, this->GetSize().GetWidth(), GetSize().GetHeight());
}
how to change NSTable selected row background color?
here is good answer, but it is for uitable view .
For now,what I see is that I can change selected hilight style :
MyTAble.SelectionHighlightStyle = NSTableViewSelectionHighlightStyle.Regular;
But here is only 3 options;
None = -1L,
Regular,
SourceList
I have tried following solution :
patientListDelegate.SelectionChanged += (o, e) => {
var r = PatientTableView.SelectedRow;
var v = PatientTableView.GetRowView (r, false);
v.Emphasized = false;
};
It works normally , but if I minimize and then open application again , still shows blue color
I found answer in objective-c
Change selection color on view-based NSTableView
Here is c# implementation:
inside delegate :
public override NSTableRowView CoreGetRowView (NSTableView tableView, nint row)
{
var rowView = tableView.MakeView ("row", this);
if (rowView == null) {
rowView = new PatientTableRow ();
rowView.Identifier = "row";
}
return rowView as NSTableRowView;
}
and custom row :
public class PatientTableRow : NSTableRowView
{
public override void DrawSelection (CGRect dirtyRect)
{
if (SelectionHighlightStyle != NSTableViewSelectionHighlightStyle.None) {
NSColor.FromCalibratedWhite (0.65f, 1.0f).SetStroke ();
NSColor.FromCalibratedWhite (0.82f, 1.0f).SetFill ();
var selectionPath = NSBezierPath.FromRoundedRect (dirtyRect, 0, 0);
selectionPath.Fill ();
selectionPath.Stroke ();
}
}
}
I'm working with a treeview, which contains several columns, also one displaying a pixbuf, if audio is playing or paused. If the user double clicks on one row, audio playback starts and the row needs to be rerendered in order to display the pixbuf icon. I used QueueDraw for this, but that does only work, if the cursor leaves the current row. How can I update the pixbuf directly?
CODE:
protected void trvMainCuesheetRowActivated (object o, RowActivatedArgs args)
{
log.debug("trvMainCuesheetRowActivated called");
TreeIter ti = TreeIter.Zero;
this.lsCuesheetData.GetIter(out ti,args.Path);
if (this.lsCuesheetData.GetValue(ti,0) != null)
{
Track tCurTrack = (Track)this.lsCuesheetData.GetValue(ti,0);
if (this.objProgram.getAudioManager().getPlayState() == AudioCuesheetEditor.AudioBackend.PlayState.Stopped)
{
this.objProgram.getAudioManager().play(tCurTrack);
this.refresh();
}
else
{
if (this.objProgram.getAudioManager().getPlayState() == AudioCuesheetEditor.AudioBackend.PlayState.Playing)
{
this.objProgram.getAudioManager().seek(tCurTrack);
this.refresh();
}
}
}
}
private void renderPlaying(TreeViewColumn _tvcColumn, CellRenderer _crCell, TreeModel _tmModel, TreeIter _tiIter)
{
Track tCurTrack = (Track)_tmModel.GetValue (_tiIter, 0);
//Just display an icon, if we are playing
if (this.objProgram.getAudioManager().getPlayState() == AudioCuesheetEditor.AudioBackend.PlayState.Playing)
{
if (this.objProgram.getAudioManager().getCurrentlyPlayingTrack() == tCurTrack)
{
Gdk.Pixbuf icon = this.RenderIcon(Stock.MediaPlay, IconSize.SmallToolbar, null);
(_crCell as CellRendererPixbuf).Pixbuf = icon;
}
else
{
(_crCell as CellRendererPixbuf).Pixbuf = null;
}
}
else
{
if (this.objProgram.getAudioManager().getPlayState() == AudioCuesheetEditor.AudioBackend.PlayState.Paused)
{
if (this.objProgram.getAudioManager().getCurrentlyPlayingTrack() == tCurTrack)
{
Gdk.Pixbuf icon = this.RenderIcon(Stock.MediaPause, IconSize.SmallToolbar, null);
(_crCell as CellRendererPixbuf).Pixbuf = icon;
}
else
{
(_crCell as CellRendererPixbuf).Pixbuf = null;
}
}
else
{
(_crCell as CellRendererPixbuf).Pixbuf = null;
}
}
}
//Purpose: Function used to refresh the MainWindow depending on new options set.
public void refresh()
{
//QueueDraw is needed since it fires a signal to cellrenderers to update
this.trvMainCuesheet.QueueDraw();
this.sbMainWindow.Visible = this.objProgram.getObjOption().getBShowStatusbar();
this.mwToolbar.Visible = this.objProgram.getObjOption().getBToolbarVisible();
}
Greetings
Sven
Found the error myself.
this.objProgram.getAudioManager().getCurrentlyPlayingTrack()
didn't always return a track, where I expected one, so the renderer worked right. Bug is fixed, thanks anyway ;).