Search Unity

Table Pro: When Your Data isn't a Game

Discussion in 'Assets and Asset Store' started by slumtrimpet, Aug 15, 2015.

  1. toph_er

    toph_er

    Joined:
    May 26, 2017
    Posts:
    4
    What is the best way to sort rows by a certain column value? Lets say I have 2 columns, and want to sort alphabetically by column #1. Do I just use my table's row list (Table.rows)?
     
    Last edited: Jun 6, 2017
  2. toph_er

    toph_er

    Joined:
    May 26, 2017
    Posts:
    4
    You still haven't answered any of my questions. Pretty frustrating. I need to know which data object to sort that will affect the table.

    I also need an answer on how to fix the header row's width. The colour is off. If the header is gray, and I have max 100% width and min 100% width then the table should fit the entire table's game object. it does that. But the header is always off. I posted a screenshot to show you on my previous post. Hopefully you get back to me soon.
     
  3. slumtrimpet

    slumtrimpet

    Joined:
    Mar 18, 2014
    Posts:
    372
    For #2, you can use the "SetSelected" methods on the table and pass true to the "animate" argument.
    I need to look at number 1 and 3 a bit. Sorry for the delay in response here.
     
  4. slumtrimpet

    slumtrimpet

    Joined:
    Mar 18, 2014
    Posts:
    372
    Sorry for the delay here... believe it or not I was literally having a baby so I've been out of commission for a while.

    Anyway...

    The data sort is purely based on how you populate the data list on the table. TablePro is just the render layer so sort your data however you wish before you populate the table or re-sort the Table.data list. If you want an example of how I'm doing that (but keep in mind you can skin this cat any way you want... it's just a simple list), check out Samples/DataTable.cs OnHeaderClick method.

    TablePro uses some enumerators to maintain it's UI so deactivating it and reactivating it will lead to a bunch of problems if you don't also call the Table.StartRenderEngine() method. I'll roll a quick test case on my side to make sure you aren't hitting a more serious bug, but I'm 99% sure you just need to call StartRenderEngine again after you activate the GO.
     
    Last edited: Jun 14, 2017
  5. slumtrimpet

    slumtrimpet

    Joined:
    Mar 18, 2014
    Posts:
    372
    Ok... so for #1 and #2:

    Code (csharp):
    1.  
    2.   public void HandleSelectRandomClick() {
    3.     int idx = Random.Range(0, this.table.data.Count - 1);
    4.     this.table.SetSelected(this.table.data[idx], null, true, true);
    5.   }
    6.  
    7.   public void HandleClearSelectionClick() {
    8.     this.table.selectedDatum = null;
    9.   }
    10.  
    For #3, lets add a quick mod to the base Table.cs:

    Put this at the top around row 46:
    Code (csharp):
    1.  
    2. public bool showHoverColors = false;
    3.  
    Then update the two IsPointerOver methods in Table.cs to evaluate that bool:
    Code (csharp):
    1.  
    2.   public bool IsPointerOver(Row row) {
    3.     return this.showHoverColors && this.isTouchDevice == false && row == this.overRow;
    4.   }
    5.  
    6.   public bool IsPointerOver(Cell cell) {
    7.     return this.showHoverColors && this.isTouchDevice == false && cell == this.overCell;
    8.   }
    9.  
    [I'll expose that "showHoverColors" in the editor and include this update in the next release]
     
    Last edited: Jun 14, 2017
  6. Jatapiaro

    Jatapiaro

    Joined:
    Aug 31, 2014
    Posts:
    12
    I have a input column, but in some special cases I need to avoid the OnInputFieldChange; I mean, I don't care about the new value, I want to keep the old one.
     
    Last edited: Jun 15, 2017
  7. slumtrimpet

    slumtrimpet

    Joined:
    Mar 18, 2014
    Posts:
    372
    That's an interesting corner case you've got there... mainly you need to 'remember' the old value and just set it back as we don't really support something quite that obscure in our vanilla engine. Kind of ugly, but something like this would work fine for that:

    Code (csharp):
    1.  
    2.   private void OnInputFieldChange(Datum d, Column c, string oldVal, string newVal) {
    3.     print("Change from " + oldVal + " to " + newVal);
    4.     this.StartCoroutine(this.ResetLater(d.elements[c.idx], oldVal));
    5.   }
    6.  
    7.   IEnumerator ResetLater(Element e, string val) {
    8.     yield return new WaitForEndOfFrame();
    9.     e.value = val;
    10.   }
    11.  
     
    Last edited: Jun 15, 2017
  8. Jatapiaro

    Jatapiaro

    Joined:
    Aug 31, 2014
    Posts:
    12
    Thank you very much for your help, that works amazing! :)
     
  9. geep_

    geep_

    Joined:
    Apr 18, 2016
    Posts:
    25
    Thanks, I'll play with these ideas this coming week.
     
  10. geep_

    geep_

    Joined:
    Apr 18, 2016
    Posts:
    25
    Your suggestion for #1 (how to unselect a table programmatically) as given by HandleClearSelectionClick caused subsequent behavior problems. Is it because table.selectedColumn also needs to be nulled? Or a spurious callback is occurring? In any event, I had good results with:

    table.SetSelected(null, null, false /* doCallback */);

    So it's on to cases #2 and #3.
     
  11. geep_

    geep_

    Joined:
    Apr 18, 2016
    Posts:
    25
    BTW, congrats on the new child.
     
  12. geep_

    geep_

    Joined:
    Apr 18, 2016
    Posts:
    25
    Another minor bug with the new feature that can automatically set key-input focus when you programmatically select
    an input cell. (Let's call that "autofocus" here.)

    As background, in my Update routine I look for certain keys to move among cells, e.g.:

    Code (CSharp):
    1.  
    2.   ...
    3.         else if (Input.GetKeyDown(KeyCode.DownArrow))
    4.             MoveToCellBelow();
    5.         else if (Input.GetKeyDown(KeyCode.UpArrow))
    6.             MoveToCellAbove();
    7.    ...
    8.  
    which in turn calls, e.g.:

    Code (CSharp):
    1.  
    2.     private void MoveToCellAbove()
    3.     {
    4.         Element e = table.GetSelectedElement();
    5.         if (e == null)
    6.             return; // no selected cell
    7.         if (Convert.ToInt32(e.datum.uid) > 1)
    8.         {
    9.             table.MoveSelectionUp(false);
    10.             ... (not shown: telling other players about this selection change)
    11.         }// else don't move if we're on first row
    12.     }
    13.  
    So if I'm in a column of Input cells, I expect that as I move up and down, each new cell gets autofocus. This works, except when it doesn't. If I down-arrow until I reach the bottom of the visible rows, and continue with a few more down-arrows, causing a vertical scroll, then the traversed input cells are highlighted as selected but don't autofocus. Surprisingly, if I up-arrow, none of the input cells autofocus until I get to the row that was bottom-most before the scroll. Then, if I down-arrow, the input cells now autofocus (until I recur the problem with another scroll).

    I don't expect this is a new problem, just haven't noticed it before.
     
    Last edited: Jun 20, 2017
  13. slumtrimpet

    slumtrimpet

    Joined:
    Mar 18, 2014
    Posts:
    372
    A patch build 1.21 has been submitted to Unity to address this (and also including the other updates I added for you in our earlier discussions).

    Thanks
     
  14. gududexiaohai

    gududexiaohai

    Joined:
    Dec 27, 2016
    Posts:
    10
    Can I add column of table by clicking a button? Can it display data from Sql Server database?
     
  15. slumtrimpet

    slumtrimpet

    Joined:
    Mar 18, 2014
    Posts:
    372
    Yes.. TablePro is just an engine to render tables from a data structure that looks very much like a C# List.

    All that you describe is just implementation specific and will be up to you to figure out how to get the data from SQL into TablePro's data structure and how to implement the button click handler function to update TablePro's column definitions to show the data you need.

    So technically, yes what you describe is exactly the sort of thing TablePro is used for, but I'm concerned your question is mixing details in there that will not have anything to do with TablePro itself. I don't want the line to be blurry for you what this asset does. Let me know if any more questions on the asset functionality.
     
  16. gududexiaohai

    gududexiaohai

    Joined:
    Dec 27, 2016
    Posts:
    10
    Thank you for your response. From the example you post on Asset Store, I just know it can add row by clicking a button. I am not sure if I can add column. So did you mean I can add column by clicking a button in Table Pro?
    About displaying data from Sql Server, I know how to get data from Sql, and put them in list or array. So can I display that data in Table Pro? Thank you very much.
     
  17. slumtrimpet

    slumtrimpet

    Joined:
    Mar 18, 2014
    Posts:
    372

    The group of "AddTextColumn" calls at the top of that code screenshot are the magic you'll need when adding a new column to a table. What you'll actually do is call "ResetTable", then call "AddTextColumn" the desired number of times (optionally providing column titles and other attributes in those calls) and then populate your data and call "StartRenderEngine" again in your button click handler.

    This entire process runs quickly so will result in a new table being displayed with the additional column(s) you wanted. You'll do this process from inside your 'add column' button click handler.

    And yes, if you can get your data from your DB into a C# List you will be able to translate that into a table. Referncing the sample code above again, you'll just iterate over your List and build Datum elements just like I'm iterating over a 'for' range above.
     
  18. gududexiaohai

    gududexiaohai

    Joined:
    Dec 27, 2016
    Posts:
    10
    Thank you for your response. Sorry, I still a question. If I modify data in the table, can it be updated to the C# List ? So then I can update the data to Sql database.
    Thank you very much. Sorry to trouble you.
     
  19. slumtrimpet

    slumtrimpet

    Joined:
    Mar 18, 2014
    Posts:
    372
    It doesn't auto
    No problem! TablePro doesn't automatically relay data back out to other structures, but you can at any time iterative over the Table.datum (sudo-List element) and update external sources. So, it's doable, but you'll need to roll that bit yourself.
     
  20. gududexiaohai

    gududexiaohai

    Joined:
    Dec 27, 2016
    Posts:
    10
    Thank you for your response. Do you mean I can update the data of list through the Table.datum? I don't know what sudo-List element is. Is it list? Should I have to convert it to C# list?
    Thank you very much. I think I will buy this asset. Thank you for your patience.
     
  21. slumtrimpet

    slumtrimpet

    Joined:
    Mar 18, 2014
    Posts:
    372
    Sorry... I just meant that the Table.data object can be iterated on (like a List) and you can then update your source data from it however you wish. (need to be more careful with my terms there, didn't mean to cause confusion)

    Thanks
     
  22. gududexiaohai

    gududexiaohai

    Joined:
    Dec 27, 2016
    Posts:
    10
    Sorry to trouble you. Do you mean if I modify the data in table, it will be stored in Table.datum? Then I can get the data from Table.datum and store them in list? Sorry for so many questions.
    Thank you very much again.
     
  23. slumtrimpet

    slumtrimpet

    Joined:
    Mar 18, 2014
    Posts:
    372
    yes
     
  24. gududexiaohai

    gududexiaohai

    Joined:
    Dec 27, 2016
    Posts:
    10
    How can I get the full data of datum? using datum.elements[index].value? But I just can get one data of one column, no full data. Could you tell me about that?
    Thank you very much.
     
  25. slumtrimpet

    slumtrimpet

    Joined:
    Mar 18, 2014
    Posts:
    372
    Just treat it like a 2D array my man. There's nothing fancy about it.

    Code (csharp):
    1.  
    2.       for (int row = 0; row < table.data.Count; row++) {
    3.         Datum d = table.data[row];
    4.         for (int col = 0; col < d.elements.Count; col++) {
    5.           Element e = d.elements[col];
    6.           print(e.value);
    7.         }
    8.       }
    9.  
     
  26. Riderfan

    Riderfan

    Joined:
    Jan 10, 2013
    Posts:
    514
    Hello.

    I tried sending a question via your support website but the 'contact us' page returns a 404.

    I'm looking for a data grid solution that can be navigated via a game pad (no mouse support). I've not seen anything specific in the documentation so thought I'd post something here.

    thanks
     
  27. slumtrimpet

    slumtrimpet

    Joined:
    Mar 18, 2014
    Posts:
    372
    First off... thanks for the head's up on the 'contact us' link issue. Not cool... we'll get that fixed ASAP.

    Regarding gamepad nagivation, the TablePro Table class has methods:
    • MoveSelectionDown
    • MoveSelectionUp
    • MoveSelectionLeft
    • MoveSelectionRight
    Others have used those methods to incorporate gamepad controls into the table. It's a manual process though where you'll handle the gamepad events and call those methods as needed. Make sense? Not sure if that's what you are looking for or not, but we try and give you the hooks you need.
     
  28. MetaZhi

    MetaZhi

    Joined:
    Feb 18, 2013
    Posts:
    28
    how can I set header to be bold and body to be normal?
     
  29. slumtrimpet

    slumtrimpet

    Joined:
    Mar 18, 2014
    Posts:
    372
    You know... you're the first person to ask for that in the hundreds of time's we've sold tablepro... Um... are you using TablePro with TextMeshPro? If so, the text elements all support TextMeshPro's "Rich Text" so you can include rich text rags to make your text bold.

    If you aren't using TextMeshPro... you should be... but if you aren't, let me know and we'll add a better solution to TablePro for this using Unity's standard Text.
     
  30. grrava

    grrava

    Joined:
    Nov 11, 2012
    Posts:
    46
    I think I found a bug, in the KeyboardInput Sample scene I'm seeing this behaviour (Unity 2017.1):

    http://i.imgur.com/SYfSSgZ.gifv

    I first select a cell, then select another cell, notice how the input is done in the previous cell instead of the current. This happens only if you select a cell in the same row.

    Can this be fixed?

    Thanks,
    Alex
     
  31. slumtrimpet

    slumtrimpet

    Joined:
    Mar 18, 2014
    Posts:
    372
    Yes, was hoping Unity would fix what I consider to be a regressions bug here in 2017.1, but doesn't look like it's coming soon (if at all).

    It's related to updating positions on inactive RectTransforms. Not sure if the fact this used to work pre-2017.1 was non-intended by Unity, but I guess we'll proceed under that assumption.
     
  32. slumtrimpet

    slumtrimpet

    Joined:
    Mar 18, 2014
    Posts:
    372
    In SLS/Widgets/Table/InputCell.cs, move line 93:

    Code (csharp):
    1.  
    2.       this.gameObject.SetActive(true);
    3.  
    up to about line 65. I'll include that fix in the next update.

    The bug here is that the GameObject needs to be active BEFORE we set the position. I do still think this is a bug on Unity's part because the Editor RectTransform inspector shows the new positions and whatnot but the position of the corresponding actual stuff on the screen isn't moving. Oh well though... easy enough fix. Let me know if this resolves the issue for you please.
     
  33. grrava

    grrava

    Joined:
    Nov 11, 2012
    Posts:
    46
    It did, thank you!
     
  34. kaplica

    kaplica

    Joined:
    Feb 20, 2014
    Posts:
    87
    Hi, nice asset however I need to be able to input the data by columns instead of rows, if that makes sense?

    I have a xml file like this:

    Code (CSharp):
    1. table>
    2. <header id="0" name="Subject pronoun">
    3. <row>I</row>
    4. <row>You</row>
    5. <row>He</row>
    6. <row>She</row>
    7. <row>It</row>
    8. <row>We</row>
    9. <row>They</row>
    10. </header>
    11. <header id="1" name="'to be'">
    12. <row>am</row>
    13. <row>are</row>
    14. <row>is</row>
    15. <row>is</row>
    16. <row>is</row>
    17. <row>are</row>
    18. <row>are</row>
    19. </header>
    20. <header id="2" name="(not)">
    21. <row>(not)</row>
    22. <row>(not)</row>
    23. <row>(not)</row>
    24. <row>(not)</row>
    25. <row>(not)</row>
    26. <row>(not)</row>
    27. <row>(not)</row>
    28. </header>
    29. <header id="3" name="Proffesion">
    30. <row>a man.</row>
    31. <row>a girl.</row>
    32. <row>a boy.</row>
    33. <row>a woman.</row>
    34. <row>a doctor.</row>
    35. <row>police officers.</row>
    36. <row>dentists.</row>
    37. </header>
    38. </table>
    So creating headers is easy, I can just query xpath for all the names of headers and then run it in a for loop. What about rows though? I tried adding it using one of your examples and it ends up adding things column by column. What I need to do though is to add a column and then add all the data into THAT column.

    Thanks
     
  35. slumtrimpet

    slumtrimpet

    Joined:
    Mar 18, 2014
    Posts:
    372
    I think you're over-thinking this. :) TablePro's data is just a list or rows and you've got a list of columns... just translate your list of columns and populate the rows. That's more of just a trivial programming task than anything related to TablePro specifically isn't it?

    Maybe I'm missing something here though... can't you explain in more detail if there's some complexity here I'm missing?
     
  36. kaplica

    kaplica

    Joined:
    Feb 20, 2014
    Posts:
    87
    Well from what I can understand, you have columns, then you have Datum, and in datum each time you add an element it ends up in different column. At least that's how it works for me and it's not a behaviour that I want to achieve. I need to add a column and then below that column add data, as in vertically. I tried doing it this way currently but there is bunch of errors.

    Code (CSharp):
    1. public void InitiateTable()
    2.     {
    3.         _table.ResetTable();
    4.        
    5.         _headers = _xDoc.SelectNodes("helptiplist/helptip[@difficulty='1' and @category='1' and @lesson='1']/table/header//@name");
    6.        
    7.         for (int i = 0; i < _headers.Count; i++)
    8.         {
    9.             var header = _headers[i];
    10.             _table.AddTextColumn(header.InnerText);
    11.         }
    12.        
    13.         _table.Initialize();
    14.  
    15.         for (int h = 0; h < _headers.Count; h++)
    16.         {
    17.             _rows = _xDoc.SelectNodes(string.Format("helptiplist/helptip[@difficulty='1' and @category='1' and @lesson='1']/table/header[@id='{0}']//row", h));
    18.  
    19.             for (int r = 0; r < _rows.Count; r++)
    20.             {
    21.                 var row = _rows[r];
    22.                 Datum d = Datum.Body(r.ToString());
    23.                 d.elements.Add(row.InnerText);
    24.                 _table.data.Add(d);
    25.             }
    26.         }
    27.        
    28.         _table.StartRenderEngine();
     
  37. slumtrimpet

    slumtrimpet

    Joined:
    Mar 18, 2014
    Posts:
    372
    Yeah... what errors are you getting? Are these related to TablePro or related to parsing the XML? From a TablePro and basic column/list translation perspective, that's exactly the sort of logic you should be using. That's all there should be to it.
     
  38. kaplica

    kaplica

    Joined:
    Feb 20, 2014
    Posts:
    87
    Well I thought it would work too... It's a datum uid mismatch.
     
  39. slumtrimpet

    slumtrimpet

    Joined:
    Mar 18, 2014
    Posts:
    372
    It would probably be a good exercise to see if you can parse that XML into a plain list of string arrays first.

    C# XML parsing is yucky and your source XML is poorly structured (rows inside of header blocks? that's nuts...), and the combo of both those things is creating a headache for you.

    See if you can spit a list of string arrays to the Unity console then THAT data structure is exactly what needs to be fed into TablePro... the TablePro integration is trivial once you can parse your source data properly.
     
  40. kaplica

    kaplica

    Joined:
    Feb 20, 2014
    Posts:
    87
    Yes I know the structure is not great. However it's made this way for a reason, not by mistake. I want people with zero knowledge to edit these so they need to be idiot proof. I get the XML back parsed just fine, there is no xml errors. I just tried one of your examples on the asset's website, I made it so that it only data to one column vertically and I'm getting the same error.

    Code (CSharp):
    1. Datum Column mismatch on UID: 0
    2.  
    It appears that you must provide the same amount of columns in datum, otherwise it will throw this error. So if I want to add data only to the first column when there is 6 columns this error pops up. I have some columns blank sometimes, that might break it too then.
     
  41. slumtrimpet

    slumtrimpet

    Joined:
    Mar 18, 2014
    Posts:
    372
    So are there not always an equal number of 'row' elements under each 'header'? It's true that we are expecting each cell to have a defined value for each row in TablePro. You can provide "" where needed but you must always provide data for every cell for every row.
     
  42. kaplica

    kaplica

    Joined:
    Feb 20, 2014
    Posts:
    87
    I just wanted to load data directly under the column rather than html table style. But because of same number of columns have to be specified it won't let me do it. I gave up though now and changed the table structure, peasants will have to manage somehow... Not my problem after all :p

    thanks for help
     
  43. slumtrimpet

    slumtrimpet

    Joined:
    Mar 18, 2014
    Posts:
    372
    Ok, sorry I don't feel like I was much help here... I feel like I'm still trying to understand your issue. At the most basic level though, TablePro is intending to be built like an html table (by row not by columns)... so yeah... if you are looking to flip that construct and build by column then that's definitely a case we've never encountered and don't currently support.

    Good luck to you!
     
  44. benmcjunkin

    benmcjunkin

    Joined:
    Sep 23, 2017
    Posts:
    1
    How difficult would it be to add a column like InputColumn, but with a dropdown containing selectable values instead? Also, if you are going to implement this, it would be nice to see a dropdown that could contain sprites as well. I've built a fun little filter system by essentially having a second "filter" table with only one row of InputColumns positioned above the main table, and I can use the input from this row to filter the rows below it, but would be nice if I could force it into a dropdown box rather than requiring free-form text.

    Also, is there any way to add Tab functionality to tab to next column in a row if using InputColumns? (And Shift-Tab to move to the previous one?)
     
  45. kaplica

    kaplica

    Joined:
    Feb 20, 2014
    Posts:
    87
    Hi again,

    What's the most efficient way to change the data I want to display in the table? Each time I reset the table and changed and render data the more memory its using and eventually the app freezes.
     
  46. slumtrimpet

    slumtrimpet

    Joined:
    Mar 18, 2014
    Posts:
    372
    For the alternate data widgets question, you can implement a selection callback that handles a RectTransform argument and use that when you call the Table.Initialize() method.

    Code (csharp):
    1.  
    2. Action<Datum, Column, RectTransform> selectionCallback,
    3.  
    You then get a reference to the RectTransform of the active cell whenever a cell is selected. This will allow you to overlay and implement any advanced input widget behavior you wish.

    For the tab input field question, check out SLS/Widgets/Table/Samples/KeyboardInput.cs. We do exactly that there.

    Thanks
     
  47. slumtrimpet

    slumtrimpet

    Joined:
    Mar 18, 2014
    Posts:
    372
    Check out SLS/Widgets/Table/Samples/AutoUpdating.cs. That updates a row every 0-1 seconds and has been tested for hours with no memory issues.
     
  48. kaplica

    kaplica

    Joined:
    Feb 20, 2014
    Posts:
    87
    Thanks, I can see the rows and headers get updated, what if I want to remove the headers and put new ones in? for example I have 4 headers, but I want to get rid of them and place 14 new ones. I tried clearing the columns list but when I try to add new columns after that I get index out of range.
     
  49. slumtrimpet

    slumtrimpet

    Joined:
    Mar 18, 2014
    Posts:
    372
    For that you do have to go through the full table flow:
    • ResetTable
    • [define columns]
    • Initialize
    • [add data]
    • StartRenderEngine
    We support adding / deleting / updating rows and headers and footers but for actually changing the quantity of columns you need to basically destroy the table and start over. The engine unfortunately was just never made expecting dynamic columns vs rows and that would be a pretty large undertaking to try and update it to flow like you are describing.
     
  50. Kirch21

    Kirch21

    Joined:
    Sep 28, 2017
    Posts:
    8
    Hello! Your asset has been working great for me so far and I just had a couple questions. How to you change the table to use TextMeshPro instead, and is it possible to set the color of a single datum row dynamically? Thanks!
     
    Last edited: Oct 5, 2017