[GH-ISSUE #72] An empty row in the bottom of flex/grid? #54

Closed
opened 2026-03-04 01:01:29 +03:00 by kerem · 4 comments
Owner

Originally created by @lesovsky on GitHub (Mar 11, 2018).
Original GitHub issue: https://github.com/rivo/tview/issues/72

Hi,

I have a layout described in the code below, and it have one thing which I can't remove - this is an empty line after flex primitive (which is consists of two textviews). Just compare two screenshots:
image
The first one is built with tview, and second one is the original interface built with ncurses. Using tview's flex or grid primitive, I've got an empty line before next primitive -- see it between MiB swap and cmd: unknown command lines. In the original interface, there is completely borderless interface with no empty lines.

How to remove this empty line?

I understand this is a stupid question and it seems very simple, and perhaps I doing things wrong, but I played a lot with primitives and can't solve my problem.

package main

import (
	ui "github.com/rivo/tview"
	"github.com/gdamore/tcell"
	"time"
	"os"
	"fmt"
)

var (
	do_quit = false

	app = ui.NewApplication()
	sys = ui.NewTextView().SetTextAlign(ui.AlignLeft).SetChangedFunc(func() { app.Draw() })
	pgo = ui.NewTextView().SetTextAlign(ui.AlignLeft).SetChangedFunc(func() { app.Draw() })
	cmdl = ui.NewTextView().SetTextAlign(ui.AlignLeft).SetChangedFunc(func() { app.Draw() })
	stat = ui.NewTextView().SetTextAlign(ui.AlignLeft).SetChangedFunc(func() { app.Draw() })

	header = ui.NewFlex().SetDirection(ui.FlexColumn).
			AddItem(sys, 0, 1, false).
			AddItem(pgo, 0, 1, false)

	flex = ui.NewFlex().SetDirection(ui.FlexRow).
			AddItem(header, 5, 1, false).
			AddItem(cmdl, 1, 1, false).
			AddItem(stat, 0, 1, false)
)

func main() {
	app.SetInputCapture(keybindings)
	app.SetRoot(flex, true)

	go showTime()

	for {
		if err := app.Run(); err != nil {
			panic(err)
		}
		if do_quit {
			break
		}
	}
}

func keybindings(event *tcell.EventKey) *tcell.EventKey {
	switch event.Key() {
	case tcell.KeyCtrlQ:
		app.Stop()
		do_quit = true
		os.Exit(0)
	case tcell.KeyRune:
		switch event.Rune() {
		default:
			printCmd("cmd: unknown command")
		}
	}
	return event
}

func showTime() {
	var pause = false

	for {
		select {
		case <-time.After(1 * time.Second):
			if pause { continue }

			cmdl.Clear()
			printSys()
			printPgo()
			printStat()
		}
	}
}

func printSys() {
	sys.Clear()
	fmt.Fprintf(sys, "pgcenter: %s\n", time.Now().Format("2006-01-02 15:04:05.000"))
	fmt.Fprintln(sys, "   %%cpu:")
	fmt.Fprintln(sys, " MiB mem:")
	fmt.Fprintln(sys, "MiB swap:")
}

func printPgo() {
	pgo.Clear()
	fmt.Fprintf(pgo, "     conn1: %s\n", time.Now().Format("2006-01-02 15:04:05.000"))
	fmt.Fprintln(pgo, "  activity:")
	fmt.Fprintln(pgo, "autovacuum:")
	fmt.Fprintln(pgo, "statements:")
}

func printCmd(s string) {
	fmt.Fprintln(cmdl, s)
}

func printStat() {
	stat.Clear()
	fmt.Fprintf(stat, "stat: %s\n", time.Now().Format("2006-01-02 15:04:05.000"))
}
Originally created by @lesovsky on GitHub (Mar 11, 2018). Original GitHub issue: https://github.com/rivo/tview/issues/72 Hi, I have a layout described in the code below, and it have one thing which I can't remove - this is an empty line after flex primitive (which is consists of two textviews). Just compare two screenshots: ![image](https://user-images.githubusercontent.com/953312/37249995-2fafba3e-2514-11e8-9740-60c91912fda3.png) The first one is built with `tview`, and second one is the original interface built with `ncurses`. Using tview's flex or grid primitive, I've got an empty line before next primitive -- see it between `MiB swap` and `cmd: unknown command` lines. In the original interface, there is completely borderless interface with no empty lines. How to remove this empty line? I understand this is a stupid question and it seems very simple, and perhaps I doing things wrong, but I played a lot with primitives and can't solve my problem. ``` package main import ( ui "github.com/rivo/tview" "github.com/gdamore/tcell" "time" "os" "fmt" ) var ( do_quit = false app = ui.NewApplication() sys = ui.NewTextView().SetTextAlign(ui.AlignLeft).SetChangedFunc(func() { app.Draw() }) pgo = ui.NewTextView().SetTextAlign(ui.AlignLeft).SetChangedFunc(func() { app.Draw() }) cmdl = ui.NewTextView().SetTextAlign(ui.AlignLeft).SetChangedFunc(func() { app.Draw() }) stat = ui.NewTextView().SetTextAlign(ui.AlignLeft).SetChangedFunc(func() { app.Draw() }) header = ui.NewFlex().SetDirection(ui.FlexColumn). AddItem(sys, 0, 1, false). AddItem(pgo, 0, 1, false) flex = ui.NewFlex().SetDirection(ui.FlexRow). AddItem(header, 5, 1, false). AddItem(cmdl, 1, 1, false). AddItem(stat, 0, 1, false) ) func main() { app.SetInputCapture(keybindings) app.SetRoot(flex, true) go showTime() for { if err := app.Run(); err != nil { panic(err) } if do_quit { break } } } func keybindings(event *tcell.EventKey) *tcell.EventKey { switch event.Key() { case tcell.KeyCtrlQ: app.Stop() do_quit = true os.Exit(0) case tcell.KeyRune: switch event.Rune() { default: printCmd("cmd: unknown command") } } return event } func showTime() { var pause = false for { select { case <-time.After(1 * time.Second): if pause { continue } cmdl.Clear() printSys() printPgo() printStat() } } } func printSys() { sys.Clear() fmt.Fprintf(sys, "pgcenter: %s\n", time.Now().Format("2006-01-02 15:04:05.000")) fmt.Fprintln(sys, " %%cpu:") fmt.Fprintln(sys, " MiB mem:") fmt.Fprintln(sys, "MiB swap:") } func printPgo() { pgo.Clear() fmt.Fprintf(pgo, " conn1: %s\n", time.Now().Format("2006-01-02 15:04:05.000")) fmt.Fprintln(pgo, " activity:") fmt.Fprintln(pgo, "autovacuum:") fmt.Fprintln(pgo, "statements:") } func printCmd(s string) { fmt.Fprintln(cmdl, s) } func printStat() { stat.Clear() fmt.Fprintf(stat, "stat: %s\n", time.Now().Format("2006-01-02 15:04:05.000")) } ```
kerem closed this issue 2026-03-04 01:01:30 +03:00
Author
Owner

@rivo commented on GitHub (Mar 11, 2018):

You're setting a fixed height of 5 lines for your header:

flex = ui.NewFlex().SetDirection(ui.FlexRow).
	AddItem(header, 5, 1, false).

If you set it to 4, the extra line will disappear.

<!-- gh-comment-id:372127982 --> @rivo commented on GitHub (Mar 11, 2018): You're setting a fixed height of `5` lines for your header: ```go flex = ui.NewFlex().SetDirection(ui.FlexRow). AddItem(header, 5, 1, false). ``` If you set it to `4`, the extra line will disappear.
Author
Owner

@lesovsky commented on GitHub (Mar 11, 2018):

If you set it to 4, the extra line will disappear.

yep, it's the first thing which I did, but after that the primitive shifts up, the first row disappears and empty line still exists.
image

<!-- gh-comment-id:372131879 --> @lesovsky commented on GitHub (Mar 11, 2018): > If you set it to 4, the extra line will disappear. yep, it's the first thing which I did, but after that the primitive shifts up, the first row disappears and empty line still exists. ![image](https://user-images.githubusercontent.com/953312/37256223-72d9b8cc-2579-11e8-9af7-4a3256089fee.png)
Author
Owner

@rivo commented on GitHub (Mar 11, 2018):

That's because the TextView will scroll with the content. Either remove the last newline:

fmt.Fprint(sys, "MiB swap:")

or call sys.ScrollToBeginning() after printing to the TextView.

<!-- gh-comment-id:372137829 --> @rivo commented on GitHub (Mar 11, 2018): That's because the `TextView` will scroll with the content. Either remove the last newline: ```go fmt.Fprint(sys, "MiB swap:") ``` or call `sys.ScrollToBeginning()` after printing to the `TextView`.
Author
Owner

@lesovsky commented on GitHub (Mar 11, 2018):

Thanks for explanation. My mistake, I must be more careful with Println().

<!-- gh-comment-id:372138056 --> @lesovsky commented on GitHub (Mar 11, 2018): Thanks for explanation. My mistake, I must be more careful with `Println()`.
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
starred/tview#54
No description provided.