New to scala and scalafx and having an issue with a tableview in a simple stock quote app [note: no prior javafx experience except in ways it is similar to things Android]
Problem: (see image) erroneous data displayed in change column where there should be none.
To create: Multiple scenarios, shown here is entry of new ticker symbol. It seems unpredictable how many cells are in error. Changing window size (say shorter then taller) generally creates more bad cells. Never happens if no change to windowsize and/or symbol list are made.
Code for the 'ticker' and 'change' columns below, though I suspect it is something in how I implemented the change column to do green/red text coloring.
(Note: data is updated in a single batch periodically which is why the new symbol does not immediately display quote data)
val colTicker = new TableColumn[Quote, String] {
editable = true
text = "Ticker"
prefWidth = 80
alignmentInParent = scalafx.geometry.Pos.Center
cellValueFactory = {
_.value.ticker
}
cellFactory = _ => new TextFieldTableCell[Quote, String](new DefaultStringConverter())
onEditCommit = (evt: CellEditEvent[Quote, String]) => {
val quote: Quote = evt.rowValue
val newTickerVal: String = evt.newValue.toUpperCase()
val oldTickerVal: String = evt.oldValue
// is it a valid ticker and not a dupe or is it blank (erase old ticker)?
if ((isValidTicker(newTickerVal) || newTickerVal.length == 0) && !symbolList.contains(newTickerVal)) {
// lock in the new value on the screen
quote.ticker.set(newTickerVal)
// if the new value is not empty add it to symbol list
if (newTickerVal.length > 0) {
symbolList.append(newTickerVal)
}
// now delete the old value
symbolList -= oldTickerVal
// sort and add another blank line
characters.sortWith(_.ticker.getValueSafe < _.ticker.getValueSafe)
if (oldTickerVal.length < 1) characters += Quote()
// now need to update the data file
putListToFile(dataFile, symbolList.sorted)
} else {
// bad ticker so keep the old one and don't update file
quote.ticker.set(oldTickerVal)
evt.getTableView.getColumns.get(0).setVisible(false)
evt.getTableView.getColumns.get(0).setVisible(true)
println("bad ticker, exiting symbol list: " + symbolList)
}
}
}
val colLast = new TableColumn[Quote, String] {
editable = false
text = "Last"
cellValueFactory = {
_.value.last
}
prefWidth = 80
alignmentInParent = scalafx.geometry.Pos.Center
}
val colChange = new TableColumn[Quote, String] {
editable = false
text = "Change"
cellFactory = {
_ =>
new TableCell[Quote, String] {
item.onChange { (_, _, newChange) =>
if (newChange != null) {
if (newChange.toString.contains("+")) textFill = Color.Green
else textFill = Color.Red
text = newChange
}
}
}
}
cellValueFactory = {
_.value.change
}
prefWidth = 80
alignmentInParent = scalafx.geometry.Pos.Center
}
JavaFX is reusing cells when rendering. This is especially noticeable when dynamically updating TableView content. Your cellFactory has to clear cell content when receiving and empty or null item: text and graphic need to be set to null. It may be sufficient to simply check for newChange == null
cellFactory = { _ =>
new TableCell[Quote, String] {
item.onChange { (_, _, newChange) =>
if (newChange == null) {
text = null
graphic = null
else {
if (newChange.toString.contains("+")) textFill = Color.Green
else textFill = Color.Red
text = newChange
}
}
}
}
It that is nor reliable you will have to implement the cellFactory the JavaFX way by implementing javafx.scene.control.TableCell and overwriting method updateItem that is passing in the empty flag:
cellFactory = {_ =>
new javafx.scene.control.TableCell[Quote, String] {
override def updateItem(item: String, empty: Boolean): Unit = {
super.updateItem(item, empty)
if (item == null || empty) {
text = null
graphic = null
}
else {
...
}
}
}
}
Related
Hi I have 4 variables and I want to refer to one of them depending on some conditions, my current code looks as follows:
switch color {
case .Azul:
botonACambiar.tintColor = colores.salidaAzul
if backTees == true {
if option == 1{self.colorHcpBackTees1 = .Azul} else{self.colorHcpBackTees2 = .Azul}
} else {
if option == 1{self.colorHcpFrontTees1 = .Azul} else{self.colorHcpFrontTees2 = .Azul}
}
...
...
case . Cafe:
botonACambiar.tintColor = colores.salidaMarron
if backTees == true {
if option == 1{self.colorHcpBackTees1 = .Cafe} else{self.colorHcpBackTees2 = .Cafe}
} else {
if option == 1{self.colorHcpFrontTees1 = .Cafe} else{self.colorHcpFrontTees2 = .Cafe}
}
}
I have around 8 options, and as you can see it gets kind of messy.
So far I only have 4 different variables that i might manipulate:
Option 1 & 2 for FrontTees & option 1 & 2 for BackTees, but in the future the app might support more options and more colors for front and back tees.
This 4 values are saved in the app and because of this I need to keep track of them individually, thus I have the four variables:
var colorHcpBackTees1: ColoresDeSalidas = .Negra
var colorHcpBackTees2: ColoresDeSalidas = .Blanca
var colorHcpFrontTees1: ColoresDeSalidas = .Roja
var colorHcpFrontTees2: ColoresDeSalidas = .Blanca
Each with their default values, it would be nice to have a way of initializing a reference variable in such a way that I could do something like:
var choice: ColoresDeSalidas{
if backTees && option == 1 { return self.colorHcpBackTees1}
if backTees && option == 2 { return self.colorHcpBackTees2}
if !backTees && option == 1 { return self.colorHcpFrontTees1}
if !backTees && option == 2 { return self.colorHcpFrontTees2}
}
And simply use the variable choice to manipulate the value of the right variable
You can accomplish this using a ReferenceWritableKeyPath.
What is a ReferenceWritableKeyPath?
Think of it as a precise description of a property in a class or struct. A real world example would be The Empire State Building instead of the address which would be 20 W 34th St, New York, NY 10001. You could tell either one to a cab driver and she could take you there.
A ReferenceWritableKeyPath is a generic type. You need to specify the class or struct name and the type of the variable you will be accessing. So your choice variable would be a ReferenceWritableKeyPath<YourClass,ColoresDeSalidas>.
Here is a standalone example:
enum ColoresDeSalidas : String {
case Negra
case Blanca
case Roja
case Azul
case Verde
}
class Foo {
var backTees = false
var option = 1
var colorHcpBackTees1: ColoresDeSalidas = .Negra
var colorHcpBackTees2: ColoresDeSalidas = .Blanca
var colorHcpFrontTees1: ColoresDeSalidas = .Roja
var colorHcpFrontTees2: ColoresDeSalidas = .Blanca
var choice: ReferenceWritableKeyPath<Foo,ColoresDeSalidas> {
if backTees && option == 1 { return \.colorHcpBackTees1 }
if backTees && option == 2 { return \.colorHcpBackTees2 }
if !backTees && option == 1 { return \.colorHcpFrontTees1 }
if !backTees && option == 2 { return \.colorHcpFrontTees2 }
fatalError("We were supposed to return a keyPath for choice")
}
func test() {
backTees = true
option = 2
print("Before: \(self.colorHcpBackTees2)")
// Now update the correct property using the choice KeyPath
self[keyPath: choice] = .Azul
print("After: \(self.colorHcpBackTees2)")
backTees = false
option = 1
// Assign it to another variable, just to show you can
let choiceFront1 = choice
option = 2
// choiceFront1 still refers to !backTees and option 1
// even though option and choice have changed
print("colorHcpFrontTees1 = \(self[keyPath: choiceFront1])")
colorHcpFrontTees1 = .Verde
print("colorHcpFrontTees1 = \(self[keyPath: choiceFront1])")
}
}
Run the test:
Foo().test()
Output:
Before: Blanca
After: Azul
colorHcpFrontTees1 = Roja
colorHcpFrontTees1 = Verde
To clean the code you could wrap the logic for initialising the properties within the enum itself.
extension ColoresDeSalidas {
init?(isBackTee: Bool, option: Int) {
switch (isBackTee, option) {
case (true, 1): self = .colorHcpBackTees1
case (true, 2(: self = .colorHcpBackTees2
case (false, 1): self = .colorHcpFrontTees1
case (false, 2): self = .colorHcpFrontTees2
default: return nil //or assign a default and make non-failable
}
And then you can initialise / update with:
let myVar = ColoresDeSalidas(isBackTee: true, option: 1)
I am reading a file that contain 277272 lines with Int triples (s,p,o) like:
10,44,22
10,47,12
15,38,3
15,41,30
16,38,5
16,44,15
16,47,18
22,38,21
22,41,42
34,44,40
34,47,36
40,38,39
40,41,42
45,38,27
45,41,30
46,44,45
46,47,48
From this file I create a Random access file object in order to navigate trough this file. However I want to extract some specific values that are in the first column, an example can be that I want to extract the values of the row that contains 16 in the first column, then I choose a pointer that is in the half, something like:
var lengthfile = (file.length().asInstanceOf[Int])
var initpointer = lengthfile/2
Then I analize if the first value is 16, if not I did a procedure to move the pointer to the nextlines, or as in this case in the back lines. Once I detect that the first value is 16, I need to know if it was in the first row, the sceond or the last one. The functions that I present here are to get the first value of the line where I have the pointer, and to know the first value from the next line.
def firstvalue(pf: Int, file:RandomAccessFile): List[Int] ={
//val file = new RandomAccessFile(filename, "r")
var pointer = pf
var flag = true
var fline = Option("a")
if (pointer <= file.length()-1){
file.seek(pointer)
fline = Option(file.readLine)
}
else {
pointer = file.length().toInt-12
file.seek(pointer)
fline = Option(file.readLine)
}
while (flag)
{
if (fline.get != "")
{
if (pointer == 0)
{
file.seek(pointer)
fline = Option(file.readLine)
pointer -= 1
flag = false
}
else{
pointer -= 1
file.seek(pointer)
fline = Option(file.readLine)
}
}
else if (fline.get == ""){
flag = false
}
}
pointer += 1
file.seek(pointer)
val line = Option(file.readLine)
val spl = line.get.split(',')
val p = spl.apply(0).toInt
//file.close()
val l = pointer :: p :: Nil
l
}
//def nextvalue(pf: Int, filename:String): List[Int] = {
//val file = new RandomAccessFile(filename, "r")
def nextvalue(pf: Int, file:RandomAccessFile): List[Int] = {
//val file = new RandomAccessFile(filename, "r")
var pointer = pf
var p = 0
var flag = true
var lastline = false
var fline = Option ("a")
if (pointer <= file.length()-1){
file.seek(pointer)
fline = Option(file.readLine)
}
//fline = Option(file.readLine)
while (flag){
if (fline.get != "")
{
if (fline == None)
{
flag = false
lastline = true
}
else{
pointer = file.getFilePointer.toInt
fline = Option(file.readLine)
flag = false
}
}
else if (fline.get == ""){
fline = Option(file.readLine)
flag = false
}
}
if (lastline == false)
{
//file.close()
if (fline != None){
val spl = fline.get.split(',')
p = spl.apply(0).toInt
}
}
val l = pointer :: p :: Nil
l
}
However I have a prformance problem, because I am reading character by character, I am trying to fix that during a lot of days, and I don't have a solution. I don't know If perhaps the file object have a function to read back lines, or something that allows to me improve this code? How can I improve this code?
Source
.fromFile(file)
.getLines
.zipWithIndex
.filter(_._1.startsWith("16,"))
Will give you all lines, that start with "16", along with their indices in the file. That should be faster then seeking back and forth ...
I have the following code :
def generateStoriesnew(outputPath: String, groupedRDD:RDD[(String,Iterable[String])], isInChurnMode: Boolean, isInChurnPeriod: Boolean) {
val windowedRDD = groupedRDD.map(SOME CODE)
var windowedRDD2 = windowedRDD.filter(r => r != null).map(a=>a.churnPeriod(isInChurnPeriod,isInChurnMode))
val prettyStringRDD = windowedRDD2.map(r => {
r.toString
})
prettyStringRDD.saveAsTextFile(outputPath)
}
and here is the code for ChurnPriod function:
def churnPeriod( churnPeriod:Boolean, churnMode: Boolean): Unit = {
if (churnMode && rootEventType.equalsIgnoreCase("c")){
var churnCustStory: CustStoryN = null
var nonChurnCustStory: CustStoryN = null
var churnPeriodEventStory: mutable.MutableList[StoryEventN] = null
var NonChurnEventstory: mutable.MutableList[StoryEventN] = null
churnPeriodEventStory = new mutable.MutableList[StoryEventN]
NonChurnEventstory = new mutable.MutableList[StoryEventN]
var lastEventChurnPeriod = true
var currentEventStory = eventStory
var max = currentEventStory.length
println(max);
if (currentEventStory.size > 0) {
for (i <- 0 until currentEventStory.length) {
var currentEvent = currentEventStory(i)
if (currentEvent.timeSenseRootEvent < 90) {
churnPeriodEventStory.+=(currentEvent)
//lastEventChurnPeriod = true
}
else {
NonChurnEventstory.+=(currentEvent)
lastEventChurnPeriod = false
}
}
}
if (churnPeriod)
eventStory = churnPeriodEventStory
else
eventStory=null
}
}
but churn period function does not change eventstory which is a member of a custstory class. what am I missing here ?
class CustStoryN (val custId:String,
var rootEventType:String,
var rootEventTime:Long,
var eventStory:mutable.MutableList[StoryEventN])
my hypothesis is either:
1.map is not the right transformation for the function that I have
2.churnPeriod function never get called
3.I can not change eventstory which is a member of cust story class
Does anyone have any idea how I can troubleshoot this problem?
This would be trivial to determine by debugging. Just put a few breakpoints and you can see if the program stops inside the function, and what transformations do occur.
My guess would be that the problem is this line: if (currentEventStory.size > 0), thus, a list that starts at size 0 remains at size 0 forever. Another option is that churnPeriod is never true, thus, you compute a lot but never assign to the eventStory variable.
Your code does need a good cleanup ;-)
I'm getting frustrated trying to convert a small part of the Golang templating language to Scala.
Below are the key parts of the lex.go source code: https://github.com/golang/go/blob/master/src/text/template/parse/lex.go
The tests are here: https://github.com/golang/go/blob/master/src/text/template/parse/lex_test.go
Basically this "class" takes a string and returns an Array of "itemType". In the template string, the start and end of special tokens is using curly braces {{ and }}.
For for example:
"{{for}}"
returns an array of 4 items:
item{itemLeftDelim, 0, "{{" } // scala case class would be Item(ItemLeftDelim, 0, "")
item{itemIdentifier, 0, "for"}
item{itemRightDelim, 0, "}}"}
item{itemEOF, 0, ""}
The actual call would look like:
l := lex("for", `{{for}}`, "{{", "}}") // you pass in the start and end delimeters {{ and }}
for {
item := l.nextItem()
items = append(items, item)
if item.typ == itemEOF || item.typ == itemError {
break
}
}
return
The key parts of the source code are below:
// itemType identifies the type of lex items.
type itemType int
const (
itemError itemType = iota // error occurred; value is text of error
itemEOF
itemLeftDelim // left action delimiter
// .............. skipped
)
const (
leftDelim = "{{"
rightDelim = "}}"
leftComment = "/*"
rightComment = "*/"
)
// item represents a token or text string returned from the scanner.
type item struct {
typ itemType // The type of this item.
pos Pos // The starting position, in bytes, of this item in the input string.
val string // The value of this item.
}
// stateFn represents the state of the scanner as a function that returns the next state.
type stateFn func(*lexer) stateFn
// lexer holds the state of the scanner.
type lexer struct {
name string // the name of the input; used only for error reports
input string // the string being scanned
leftDelim string // start of action
rightDelim string // end of action
state stateFn // the next lexing function to enter
pos Pos // current position in the input
start Pos // start position of this item
width Pos // width of last rune read from input
lastPos Pos // position of most recent item returned by nextItem
items chan item // channel of scanned items
parenDepth int // nesting depth of ( ) exprs
}
// lex creates a new scanner for the input string.
func lex(name, input, left, right string) *lexer {
if left == "" {
left = leftDelim
}
if right == "" {
right = rightDelim
}
l := &lexer{
name: name,
input: input,
leftDelim: left,
rightDelim: right,
items: make(chan item),
}
go l.run()
return l
}
// run runs the state machine for the lexer.
func (l *lexer) run() {
for l.state = lexText; l.state != nil; {
l.state = l.state(l)
}
}
// nextItem returns the next item from the input.
func (l *lexer) nextItem() item {
item := <-l.items
l.lastPos = item.pos
return item
}
// emit passes an item back to the client.
func (l *lexer) emit(t itemType) {
l.items <- item{t, l.start, l.input[l.start:l.pos]}
l.start = l.pos
}
// lexText scans until an opening action delimiter, "{{".
func lexText(l *lexer) stateFn {
for {
if strings.HasPrefix(l.input[l.pos:], l.leftDelim) {
if l.pos > l.start {
l.emit(itemText)
}
return lexLeftDelim
}
if l.next() == eof {
break
}
}
// Correctly reached EOF.
if l.pos > l.start {
l.emit(itemText)
}
l.emit(itemEOF)
return nil
}
// next returns the next rune in the input.
func (l *lexer) next() rune {
if int(l.pos) >= len(l.input) {
l.width = 0
return eof
}
r, w := utf8.DecodeRuneInString(l.input[l.pos:])
l.width = Pos(w)
l.pos += l.width
return r
}
// lexLeftDelim scans the left delimiter, which is known to be present.
func lexLeftDelim(l *lexer) stateFn {
l.pos += Pos(len(l.leftDelim))
if strings.HasPrefix(l.input[l.pos:], leftComment) {
return lexComment
}
l.emit(itemLeftDelim)
l.parenDepth = 0
return lexInsideAction
}
// lexRightDelim scans the right delimiter, which is known to be present.
func lexRightDelim(l *lexer) stateFn {
l.pos += Pos(len(l.rightDelim))
l.emit(itemRightDelim)
return lexText
}
// there are more stateFn
So I was able to write the item and itemType:
case class Item(typ: ItemType, pos: Int, v: String)
sealed trait ItemType
case object ItemError extends ItemType
case object ItemEOF extends ItemType
case object ItemLeftDelim extends ItemType
...
..
.
The stateFn and Lex definitions:
trait StateFn extends (Lexer => StateFn) {
}
I'm basically really stuck on the main parts here. So things seem to be kicked of like this:
A Lex is created, then "go l.run()" is called.
Run is a loop, which keeps looping until EOF or an error is found.
The loop initializes with lexText, which scans until it finds an {{, and then it sends a message to a channel with all the preceding text of type 'itemText', passing it an 'item'. It then returns the function lexLeftDelim. lexLeftDelim does the same sort of thing, it sends a message 'item' of type itemLeftDelim.
It keeps parsing the string until it reaches EOF basically.
I can't think in scala that well, but I know I can use an Actor here to pass it a message 'Item'.
The part of returning a function, I asked I got some good ideas here: How to model recursive function types?
Even after this, I am really frustrated and I can seem to glue these concepts together.
I'm not looking for someone to implement the entire thing for me, but if someone could write just enough code to parse a simple string like "{{}}" that would be awesome. And if they could explain why they did a certain design that would be great.
I created a case class for Lex:
case class Lex(
name: String,
input: String,
leftDelim: String,
rightDelim: String,
state: StateFn,
var pos: Int = 0,
var start: Int = 0,
var width: Int = 0,
var lastPos: Int = 0,
var parenDepth: Int = 0
) {
def next(): Option[String] = {
if (this.pos >= this.input.length) {
this.width = 0
return None
}
this.width = 1
val nextChar = this.input.drop(this.pos).take(1)
this.pos += 1
Some(nextChar)
}
}
The first stateFn is LexText and so far I have:
object LexText extends StateFn {
def apply(l: Lexer) = {
while {
if (l.input.startsWith(l.leftDelim)) {
if (l.pos > l.start) {
// ????????? emit itemText using an actor?
}
return LexLeftDelim
}
if (l.next() == None) {
break
}
}
if(l.pos > l.start) {
// emit itemText
}
// emit EOF
return None // ?? nil? how can I support an Option[StateFn]
}
}
I need guidance on getting the Actor's setup, along with the main run loop:
func (l *lexer) run() {
for l.state = lexText; l.state != nil; {
l.state = l.state(l)
}
}
This is an interesting problem domain that I tried to tackle using Scala, and so far I am a bit confused hoping some else finds it interesting and can work with what little I have so far and provide some code and critique if I am doing it correctly or not.
I know deep down I shouldn't be mutating, but I'm still on the first few pages of the functional book :)
If you translate the go code literally into Scala, you'll get very unidiomatic piece of code. You'll probably get much more maintainable (and shorter!) Scala version by using parser combinators. There are plenty of resources about them on the internet.
import scala.util.parsing.combinator._
sealed trait ItemType
case object LeftDelim extends ItemType
case object RightDelim extends ItemType
case object Identifier extends ItemType
case class Item(ty: ItemType, token: String)
object ItemParser extends RegexParsers {
def left: Parser[Item] = """\{\{""".r ^^ { _ => Item(LeftDelim, "{{") }
def right: Parser[Item] = """\}\}""".r ^^ { _ => Item(RightDelim, "}}") }
def ident: Parser[Item] = """[a-z]+""".r ^^ { x => Item(Identifier, x) }
def item: Parser[Item] = left | right | ident
def items: Parser[List[Item]] = rep(item)
}
// ItemParser.parse(ItemParser.items, "{{foo}}")
// res5: ItemParser.ParseResult[List[Item]] =
// [1.8] parsed: List(Item(LeftDelim,{{), Item(Identifier,foo), Item(RightDelim,}}))
Adding whitespace skipping, or configurable left and right delimiters is trivial.
I have 1 problem and 1 question when using BSONDocument getAs.
Whenever I try to access the value l in the format below by calling this:
docFound.getAs[Int]("v.1.0.2013.9.9.l")
it returns None. However if I do:
docFound.getAs[BSONDocument]("v")
it returtns a valid BSONDocument for the whole v section. What is wrong in my first call? Does reactivemongo support path traversal?
BSONDocument: {
v: {
1.0: {
2013: {
9: {
9: {
l: BSONInteger(0),
s: BSONInteger(8)
}
}
}
}
}
}
The second question is:
I find a document in DB with the following filter:
BSONDocument(
"_id" -> 0,
"v.1.0.2013.9.9.l" -> 1)
But it seems like instead of extracting just these values "_id" & "l" it extracts the whole document. When I do BSONDocument.pretty(foundDoc) I see the whole document, not just "l" value that I have requested. Please clarify if it is even worth specifying fields I am interested in if it always downloads the whole document.
Thanks.
It seems like according to the sources it is not supported in reactivemongo. So I have created a quick helper:
def getAsByPath[T](path: String, doc: BSONDocument)
(implicit reader: BSONReader[_ <: BSONValue, T]): Option[T] = {
val pathChunks = path.split('.')
var pathIndex = 0
var curDoc: Option[BSONDocument] = Some(doc)
var currentChunk = ""
while(pathIndex != pathChunks.size) {
currentChunk += pathChunks(pathIndex)
// If this is the last chunk it must be a value
// and if previous Doc is valid let's get it
if (pathIndex == pathChunks.size - 1 && curDoc != None)
return curDoc.get.getAs[T](currentChunk)
val tmpDoc = curDoc.get.getAs[BSONDocument](currentChunk)
if (tmpDoc != None) {
currentChunk = ""
curDoc = tmpDoc
} else {
// We need to support this as sometimes doc ID
// contain dots, for example "1.0"
currentChunk += "."
}
pathIndex += 1
}
None
}
However my second question is still valid. If someone knows please let me know.