Showing after hiding window removes all content - user-interface

I am using following code which produces a main window with a button to open other window. I want to be able to repeatedly hide and show other window. Closing main window should exit the program:
package main
import ("github.com/andlabs/ui")
func main() {
ui.Main(makeAllWins)
}
var mainWindow *ui.Window
var otherWindow *ui.Window
func makeAllWins(){
makeMainWin()
makeOtherWin()
mainWindow.Show()
}
func makeMainWin(){
var otherButton = ui.NewButton("Other module")
otherButton.OnClicked( func (*ui.Button) { otherWindow.Show() })
var box = ui.NewVerticalBox()
box.Append(ui.NewLabel("Select module"), false)
box.Append(otherButton, false)
mainWindow = ui.NewWindow("Hello", 200, 100, false)
mainWindow.SetChild(box)
mainWindow.OnClosing( func (*ui.Window) bool { ui.Quit(); return true } )
}
func makeOtherWin(){
var box = ui.NewVerticalBox()
box.Append(ui.NewLabel("label1"), false)
box.Append(ui.NewLabel("label2"), false)
box.Append(ui.NewLabel("label3"), false)
otherWindow = ui.NewWindow("Other", 200, 100, false)
otherWindow.SetChild(box)
otherWindow.OnClosing( func (*ui.Window) bool { otherWindow.Hide(); return true } ) // I THINK PROBLEM IS IN THIS LINE
}
However, when I show the other window after hiding it once, all the labels are gone. On repeating, the program crashes with following error:
fatal error: unexpected signal during runtime execution
[signal SIGSEGV: segmentation violation code=0x1 addr=0x67fb0a pc=0x67fb0a]
Where is the problem and how can it be solved. Thanks for your help.

Here:
otherWindow.OnClosing( func (*ui.Window) bool { otherWindow.Hide(); return true } )
you should be returning false instead of true. As it is, the window is getting destroyed when you close it, leading to the segmentation fault when you try to reference it later.
Per the documentation comments:
OnClosing registers f to be run when the user clicks the Window's
close button. Only one function can be registered at a time. If f
returns true, the window is destroyed with the Destroy method. If f
returns false, or if OnClosing is never called, the window is not
destroyed and is kept visible.

Related

How to extend fyne BaseWidget - go gives error "type *SimpleCard has no field or method super"

I'm trying to extend fyne widget to have a simple clickable content with background.
I searched fyne widgets to find an example that could be used as a starter and found something similar in List/ListItem.
I basically copied the list item code and adapted it a little bit.
It does look similar to the simpler example on fyne documentation.
But for some unknown reason go gives me an error and I don't know what the cause is or how I can fix it:
custom_widget/simple_card.go:80:24: c.card.super undefined (type *SimpleCard has no field or method super)
Here is the code of the module (custom_widget/simple_card.go):
package custom_widget
import (
"fyne.io/fyne/v2"
"fyne.io/fyne/v2/canvas"
"fyne.io/fyne/v2/theme"
"fyne.io/fyne/v2/widget"
"log"
)
// Declare conformity with interfaces.
var _ fyne.Widget = (*SimpleCard)(nil)
var _ fyne.Tappable = (*SimpleCard)(nil)
type SimpleCard struct {
widget.BaseWidget
onTapped func()
background *canvas.Rectangle
content fyne.CanvasObject
selected bool
}
func NewSimpleCard(content fyne.CanvasObject, tapped func()) *SimpleCard {
card := &SimpleCard{onTapped: tapped, content: content}
card.ExtendBaseWidget(card)
return card
}
// CreateRenderer is a private method to Fyne which links this custom_widget to its renderer.
func (c *SimpleCard) CreateRenderer() fyne.WidgetRenderer {
c.ExtendBaseWidget(c)
c.background = canvas.NewRectangle(theme.SelectionColor())
c.background.Hide()
objects := []fyne.CanvasObject{c.background, c.content}
// NewBaseRenderer and BaseRenderer are copied from
// https://github.com/fyne-io/fyne/blob/master/internal/widget/base_renderer.go
// because the functionality is marked internal in fyne !?
return &SimpleCardRenderer{NewBaseRenderer(objects), c}
}
func (c *SimpleCard) Tapped(_ *fyne.PointEvent) {
log.Println("I have been tapped")
if c.onTapped != nil {
c.selected = true
c.Refresh()
c.onTapped()
}
}
// Declare conformity with the WidgetRenderer interface.
var _ fyne.WidgetRenderer = (*SimpleCardRenderer)(nil)
type SimpleCardRenderer struct {
BaseRenderer
card *SimpleCard
}
// MinSize calculates the minimum size of a SimpleCardRenderer.
// This is based on the size of the status indicator and the size of the child object.
func (c *SimpleCardRenderer) MinSize() fyne.Size {
return c.card.content.MinSize()
}
// Layout the components of the SimpleCardRenderer custom_widget.
func (c *SimpleCardRenderer) Layout(size fyne.Size) {
c.card.background.Resize(size)
c.card.content.Resize(size)
}
func (c *SimpleCardRenderer) Refresh() {
if c.card.selected {
c.card.background.FillColor = theme.SelectionColor()
c.card.background.Show()
} else {
c.card.background.Hide()
}
c.card.background.Refresh()
canvas.Refresh(c.card.super()) // compiler error !
}
Remove all of the renderer type you created and in the CreateRenderer just return widget.NewSimpleRenderer(container .NewMax(c.background, c.content)). It is simpler than you think.
Copying code out of the main widgets is often not the best way as we have shortcuts and/or must support more functionality than your own widgets.

I'm writing a basic command line (UDP) server/listener in swift using Xcode. #GCDAsyncUdpSocket doesnt call any of my delegates

This is my very first program in Swift. I'm writing a basic command line (UDP) server/listener in swift using Xcode. I'm able to send data i.e. a string with characters 'testing' via the "sendData" call (verified through wireshark). However I can't seem to invoke any of the delegate callbacks. For "sendData", I've checked the implementation within #GCDAsyncUdpSocket's main file and I see that none of the delegates are called unless send we see a particular error (resolve error) in which case the "didNOTSendDataWithTag" is called.
But if "beginReceiving" is called, it does NOT invoke "didReceiveData" callback. I cant seem to find figure out why. Also "beginReceiving is suppose to be recursive (Calls itself forever I assume) according to its implementation. But my program exits quickly without any errors. Any help will be really appreciated.
import Cocoa
import CocoaAsyncSocket
class udpListener : GCDAsyncUdpSocketDelegate {
var udpSock : GCDAsyncUdpSocket?
let listenPort : UInt16 = 14000
let data = "testing".dataUsingEncoding(NSUTF8StringEncoding)
let toAddress = "127.0.0.1"
let connectPort : UInt16 = 14001
init () {
udpSock = GCDAsyncUdpSocket(delegate: self, delegateQueue: dispatch_get_main_queue())
do {
try udpSock!.bindToPort(listenPort, interface: "lo0") // Swift automatically translates Objective-C methods that produce
// errors into methods that throw an error according to Swift’s native error handling functionality.
}
catch _ as NSError {
print("Issue with binding to Port")
return }
do {
try udpSock!.beginReceiving()
}
catch _ as NSError {
print("Issue with receciving data")
return }
}
func sendData() {
udpSock!.sendData(data, toHost: toAddress, port: connectPort, withTimeout: -1, tag: 0)
}
}
// Delegate CallBacks
#objc func udpSocket(sock: GCDAsyncUdpSocket!, didReceiveData data: NSData!, fromAddress address: NSData!, withFilterContext filterContext: AnyObject!) {
let str = NSString(data: data!, encoding: NSUTF8StringEncoding)
print(str)
}
#objc func udpSocket(sock: GCDAsyncUdpSocket!, didSendDataWithTag tag: Int) {
print("didSendDataWithTag")
}
#objc func udpSocket(sock: GCDAsyncUdpSocket!, didNotSendDataWithTag tag: Int, dueToError error: NSError!) {
print("didNOTSendDataWithTag")
}
}
I'm instantiating an instance of the class from the main swift file and calling its methods in this order. Is this correct or am I missing something here
import Foundation
var dnsListener = udpListener()
dnsListener.sendData()
Here's the screenshot of the wireshark results
The main thread does not have any loop to keep it from exiting, so the execution is finished before the message is sent. If a loop or delay is added to main(), the message will be sent.
The other problem with this code is that the delegates are set to run on the main queue. The main queue is busy running the loop or delay, and can not execute the delegate code. By creating a new delegate queue, the code in the delegate functions will run.
The following code works in Swift 3.
Main code:
import Foundation
var dnsListener = UdpListener()
for i in 1...3 {
print("Sending data \(i)")
dnsListener.sendData()
sleep(3)
}
print("Execution finished")
UdpListener code:
import Foundation
import CocoaAsyncSocket
class UdpListener : NSObject, GCDAsyncUdpSocketDelegate {
var udpSock: GCDAsyncUdpSocket?
let listenPort: UInt16 = 14000
let data = "testing".data(using: String.Encoding.utf8)
let toAddress = "127.0.0.1"
let connectPort: UInt16 = 14001
override init() {
super.init()
let utilityQueue = DispatchQueue(label: "com.stackoverflow.UdpListener.utilityQueue", qos: .utility)
udpSock = GCDAsyncUdpSocket(delegate: self, delegateQueue: utilityQueue)
do {
try udpSock!.bind(toPort: listenPort, interface: "lo0")
} catch {
print("Issue with binding to Port")
return
}
do {
try udpSock!.beginReceiving()
} catch {
print("Issue with receciving data")
return
}
}
func sendData() {
udpSock!.send(data!, toHost: toAddress, port: connectPort, withTimeout: -1, tag: 0)
}
// Delegate CallBacks
func udpSocket(_ sock: GCDAsyncUdpSocket, didReceive data: Data, fromAddress address: Data, withFilterContext filterContext: Any?) {
let str = String(data: data, encoding: String.Encoding.utf8)
if let str = str {
print(str)
} else {
print("Could not decode received data")
}
}
func udpSocket(_ sock: GCDAsyncUdpSocket, didSendDataWithTag tag: Int) {
print("didSendDataWithTag")
}
func udpSocket(_ sock: GCDAsyncUdpSocket, didNotSendDataWithTag tag: Int, dueToError error: Error?) {
print("didNOTSendDataWithTag")
}
}

Proper way to reuse NSWindowControllers

This is a follow-up to this question.
I'm trying to create an app with a few windows that pop up on start,
and can be closed ,then opened again later.
I'm not having issues with reopening the windows anymore,
but issues with memory. It keeps going up, everytime I request those windows to show again.
Here is my code:
class AppDelegate: NSObject, NSApplicationDelegate {
var parentWC: NSWindowController?
var childWC: NSWindowController?
func showThem() {
if self.parentWC == nil {
let parentWindow = CustomWindow()
self.parentWC.window = parentWindow
}
if self.childWC == nil {
let childWindow = NSWindow()
self.childWC.window = childWindow
self.parentWC.window.addChildWindow(self.childWC.window)
}
}
func closeAllWindows() {
self.childWC.window.close()
self.parentWC.window.close()
}
// From app menu
#IBAction func showThemAgain(sender: AnyObject) {
self.parentWindow.window = nil
self.parentWC = nil
self.childWindow.window = nil
self.childWC = nil
self.showThem()
}
}
class CustomWindow: NSWindow {
func onCloseRequest() {
let appD = (NSApplication.sharedApplication().delegate) as! AppDelegate
appD.closeAllWindows()
}
}
If I'm closing the windows and settings the vars to nil, what is causing the memory usage to go up every time I show these windows? Are they not being closed?
*Note that there is a button in CustomWindow that is used for closing.

How to use NSWindowOcclusionState.Visible in Swift

I am trying to implement window toggling (something I've done many times in Objective-C), but now in Swift. It seams that I am getting the use of NSWindowOcclusionState.Visible incorrectly, but I really cannot see my problem. Only the line w.makeKeyAndOrderFront(self) is called after the initial window creation.
Any suggestions?
var fileArchiveListWindow: NSWindow? = nil
#IBAction func tougleFileArchiveList(sender: NSMenuItem) {
if let w = fileArchiveListWindow {
if w.occlusionState == NSWindowOcclusionState.Visible {
w.orderOut(self)
}
else {
w.makeKeyAndOrderFront(self)
}
}
else {
let sb = NSStoryboard(name: "FileArchiveOverview",bundle: nil)
let controller: FileArchiveOverviewWindowController = sb?.instantiateControllerWithIdentifier("FileArchiveOverviewController") as FileArchiveOverviewWindowController
fileArchiveListWindow = controller.window
fileArchiveListWindow?.makeKeyAndOrderFront(self)
}
}
Old question, but I just run into the same problem. Checking the occlusionState is done a bit differently in Swift using the AND binary operator:
if (window.occlusionState & NSWindowOcclusionState.Visible != nil) {
// visible
}
else {
// not visible
}
In recent SDKs, the NSWindowOcclusionState bitmask is imported into Swift as an OptionSet. You can use window.occlusionState.contains(.visible) to check if a window is visible or not (fully occluded).
Example:
observerToken = NotificationCenter.default.addObserver(forName: NSWindow.didChangeOcclusionStateNotification, object: window, queue: nil) { note in
let window = note.object as! NSWindow
if window.occlusionState.contains(.visible) {
// window at least partially visible, resume power-hungry calculations
} else {
// window completely occluded, throttle down timers, CPU, etc.
}
}

Swift: Error updating UI component when using a delegate

I'm trying to update a progress bar with the progress of loading a load of values into CoreData. However, whenever I try to call an update on my progressView component, I get a fatal error stating that "unexpectedly found nil while unwrapping an Optional value".
The interesting thing is that this happens even if I put 'self.progressView.progress = 0.5' in the delegate method of my program - indicating that it's the progressView component it can't find rather than an issue with the value. A quick check with println also confirms the value does exist and so isn't nil. Note that if I put the 'self.progressView.progress = 0.5' statement under a function connected directly to a button, it works fine so it must be some sort of issue with the command being called from the delegate.
Can anyone work out what I'm doing wrong here? Thanks for your help.
Delegate method:
class ViewControllerUpdate: UIViewController, NSURLSessionDelegate, NSURLSessionDownloadDelegate, saveUpdate {
[....]
func updateStatus(status: String, progress: Float?) {
if let percentProgress = progress? {
self.progressView.progress = 0.5
}
//println(progress) - NOTE THIS IS CORRECTLY POPULATED WITH THE APPROPRIATE VALUE
}
Calling class:
protocol saveUpdate {
func updateStatus(status:String, progress:Float?)
}
class sqlPullSave {
let classtoUpdate: saveUpdate = ViewControllerUpdate()
func saveTSVtoSQL(fromFile: NSURL) -> Int {
//Load up the information into a Dictionary (tsv)
//let tsvURL = NSURL(fileURLWithPath: NSBundle.mainBundle().pathForResource(fromFileName, ofType: fromFileExtension)!)
let tsvURL: NSURL = fromFile
let tab = NSCharacterSet(charactersInString: "\t")
let tsv = CSV(contentsOfURL: tsvURL, separator: tab)
//let defResult: AnyObject = tsv.rows[0]["Name"]!
//let tryagain:String = AnyObjecttoString(tsv.rows[1]["Name"]!)
//load the data into the SQLite database...
dispatch_async(dispatch_get_main_queue()) {
for a in 0..<tsv.rows.count {
self.SQLsaveLine(self.AnyObjecttoString(tsv.rows[a]["Name"]!),
name_l: "",
desc: self.AnyObjecttoString(tsv.rows[a]["1"]!),
jobTitle: self.AnyObjecttoString(tsv.rows[a]["2"]!),
extn: self.AnyObjecttoString(tsv.rows[a]["3"]!)
// update status
var percentComplete: Float = (Float(a) / Float(tsv.rows.count))
self.classtoUpdate.self.updateStatus("SQLload", progress: percentComplete)
}
}
return 0
}

Resources