Welcome!
This is the community forum for my apps Pythonista and Editorial.
For individual support questions, you can also send an email. If you have a very short question or just want to say hello β I'm @olemoritz on Twitter.
DatePicker in Countdown mode - days option?
-
Oh, I should mention that in countdown mode max hours are 23. So its not like you can select 48hrs for 2 days
-
Below is a silly example to illustrate it more clearly. In the example rather than using the datepicker as an input control, I am using it as a display. Look its not super critical, but the datepicker could be more useful with finer resolution I think.
import ui import arrow class MyTimerTest(ui.View): def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self.dp = None self.countdown_time = arrow.now().shift(days=+0, hours=+1, minutes=+3) self.make_view() self.update_interval = 1 def make_view(self): dp_mode = ui.DATE_PICKER_MODE_COUNTDOWN ''' can uncomment and try the modes below. they work ok as long as the total time is under 24hrs if you change 'self.countdown_time' params to days=+1, it all goes wrong! ''' #dp_mode = ui.DATE_PICKER_MODE_TIME #dp_mode = ui.DATE_PICKER_MODE_DATE_AND_TIME dp = ui.DatePicker(frame=self.bounds, enabled=False, mode=dp_mode) self.dp = dp self.add_subview(self.dp) def update(self): #self.update_interval = 30 if self.update_interval == 1 else 1 td = self.countdown_time - arrow.now() self.dp.countdown_duration = td.total_seconds() self.name = str(td) if __name__ == '__main__': f = (0, 0, 320, 480) tt = MyTimerTest(frame=f) tt.present('sheet')
-
@Phuket2, looks like thatβs what you get from Apple.
How about using a SceneView and modifying the experimental stopwatch from examples?
-
zrzka just posted a CollectionView example recently which probably let's you do what you want...
-
Thanks guys. I was just suprised it didn't support what I was trying to do. I wanted this sort of timer for my game I play for some time, and I always end up avoid doing it. But yesterday I thought I will just make a simple version of what I want and just get it working.
I have to say with the advent of the update method, using TinyDB and arrow that the nuts and bolts of what I wanted to do was easy. Have to say @JonB the PYUIFile Loader also added to the simplicity of putting this together all pretty quickly.
But I was suprised how it all come to a screeching halt when I wanted a UI to input my timers value. That's why I asked if this was apples implementation. Just seemed strange to me that Apple's control wouldn't have supported more. Well minimum DD:HH:MM and possibly seconds. Oh when I said it come to a screeching halt, I basically mean my rhythm was gone.
All the other nuts and bolts went fast and smooth. I wont use @zrzka control, I will do something with textfields I think for the entry and use like a progress bar/with caption to show the countdown. Later I might look at the stopwatch example again.
Also, I might look at the analog clock example again. I cant remember who, but after one of my posts a guy rewrote the analog clock to work as a ui control rather than scene. Anyway, I will take a look.
I was also a little suprised at how the notification module was working. @omz mentioned that the module needs attention, so thats nice.
Anyway, I am not bitching. Just sharing an experience in a way. I rarely write anything other than a few small tools(very smallI) actually want to use. This was not big, but I will use it. The real implementation will be using a TableView as the game I play has multiple timers running continuously and are important for the game. Some timers should automatically reset after say every 3hrs, some timers need to be reset manually approx every five days. Then need to convert some of these times to show the local time they expire etc.
The good news for me is that with the tools/libs I have this will be fairly straight fwd. The bad news for me is I let small things like the datepicker slow me down and lose my rhythm.
BTW, I am sorry I dont go looking the the apple docs myself. That would be even a further distraction, also I dont have the confidence to know whether I am going to come away with the correct answer. In case I really just wanted to know 100% from someone who understands the Obj c documentation.
Edit: I guess I really should think of a widget, this maybe would make the most sense -
@Phuket2 π with the help of @zrzka for the very complex part...
# coding: utf-8 from objc_util import ObjCInstance, c, ObjCClass, ns, create_objc_class, NSObject from ctypes import c_void_p import ui import arrow # Data for four pickers _data = [ [str(x) for x in range(0,10)], [str(x) for x in range(0, 24)], [str(x) for x in range(0,60)], [str(x) for x in range(0,60)], ] # ObjC classes UIColor = ObjCClass('UIColor') UIPickerView = ObjCClass('UIPickerView') UIFont = ObjCClass('UIFont') NSAttributedString = ObjCClass('NSAttributedString') # Default attributes, no need to recreate them again and again def _str_symbol(name): return ObjCInstance(c_void_p.in_dll(c, name)) _default_attributes = { _str_symbol('NSFontAttributeName'): UIFont.fontWithName_size_(ns('Courier'), 16), _str_symbol('NSForegroundColorAttributeName'): UIColor.blackColor(), _str_symbol('NSBackgroundColorAttributeName'): UIColor.whiteColor() } # Data source & delegate methods def pickerView_attributedTitleForRow_forComponent_(self, cmd, picker_view, row, component): tag = ObjCInstance(picker_view).tag() return NSAttributedString.alloc().initWithString_attributes_(ns(_data[tag - 1][row]), ns(_default_attributes)).ptr def pickerView_titleForRow_forComponent_(self, cmd, picker_view, row, component): tag = ObjCInstance(picker_view).tag() return ns(_data[tag - 1][row]).ptr def pickerView_numberOfRowsInComponent_(self, cmd, picker_view, component): tag = ObjCInstance(picker_view).tag() return len(_data[tag - 1]) def numberOfComponentsInPickerView_(self, cmd, picker_view): return 1 def rowSize_forComponent_(self, cmd, picker_view, component): return 100 def pickerView_rowHeightForComponent_(self, cmd, picker_view, component): return 30 def pickerView_didSelectRow_inComponent_(self, cmd, picker_view, row, component): tag = ObjCInstance(picker_view).tag() print(f'Did select {_data[tag - 1][row]}') methods = [ numberOfComponentsInPickerView_, pickerView_numberOfRowsInComponent_, rowSize_forComponent_, pickerView_rowHeightForComponent_, pickerView_attributedTitleForRow_forComponent_, pickerView_didSelectRow_inComponent_ ] protocols = ['UIPickerViewDataSource', 'UIPickerViewDelegate'] UIPickerViewDataSourceAndDelegate = create_objc_class( 'UIPickerViewDataSourceAndDelegate', NSObject, methods=methods, protocols=protocols ) # UIPickerView wrapper which behaves like ui.View (in terms of init, layout, ...) class UIPickerViewWrapper(ui.View): def __init__(self, **kwargs): super().__init__(**kwargs) self._picker_view = UIPickerView.alloc().initWithFrame_(ObjCInstance(self).bounds()).autorelease() ObjCInstance(self).addSubview_(self._picker_view) def layout(self): self._picker_view.frame = ObjCInstance(self).bounds() @property def tag(self): return self._picker_view.tag() @tag.setter def tag(self, x): self._picker_view.setTag_(x) @property def delegate(self): return self._picker_view.delegate() @delegate.setter def delegate(self, x): self._picker_view.setDelegate_(x) @property def data_source(self): return self._picker_view.dataSource() @data_source.setter def data_source(self, x): self._picker_view.setDataSource_(x) class MyTimerTest(ui.View): def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self.background_color = 'white' self.countdown_time = arrow.now().shift(days=+3, hours=+1, minutes=+3) self.make_view() self.update_interval = 1 def make_view(self): self.delegate_and_datasource = UIPickerViewDataSourceAndDelegate.alloc().init().autorelease() x = 50 dx = 100 dy = 100 for i in range(0,4): l = ui.Label(frame=(x,50,dx,dy)) l.text = ['day','hour','min','sec'][i] l.alignment = ui.ALIGN_CENTER self.add_subview(l) pv = UIPickerViewWrapper(frame=[x, 100, dx, dy]) pv.name = l.text pv.delegate = self.delegate_and_datasource pv.data_source = self.delegate_and_datasource pv._picker_view.userInteractionEnabled = False pv.tag = i + 1 self.add_subview(pv) x = x + dx def update(self): #self.update_interval = 30 if self.update_interval == 1 else 1 td = self.countdown_time - arrow.now() self.name = str(td) self.disp_counters(td) def disp_counters(self,td): days = td.days secs = td.seconds hours = int(secs/3600) secs = secs - hours*3600 mins = int(secs/60) secs = secs - mins*60 self['day']._picker_view.selectRow_inComponent_animated_(days, 0, True) self['hour']._picker_view.selectRow_inComponent_animated_(hours, 0, True) self['min']._picker_view.selectRow_inComponent_animated_(mins, 0, True) self['sec']._picker_view.selectRow_inComponent_animated_(secs, 0, True) if __name__ == '__main__': f = (0, 0, 500, 480) tt = MyTimerTest(frame=f) tt.present('sheet')
-
@cvp said:
-
@cvp , hey, thanks for going to the trouble to do this (also thanks @zrzka ). Its not important, but it wont load in the Today Widget. As I say, not important. Just as I am playing with thee TDW I thought I would give it a quick go. I didn't get things lining up correctly yet as I had to move it up a little. But it works in Pythonista, so I guess its just a memory issue. I see it flash up loading BlackMamba when its in the Today Widget, then the message comes up 'Unable to Load'. I clicked that a few times.
Again, this is just a FYI. I will tidy up my class you edited, so you can pass the time info etc to it and maybe so other useful methods/properties and repost.
Thanks again -
@cvp, was just playing around with the datepicker. But it occurred to me that if apple had included a number/float mode you could use multiple datetime controls to create a input view with many possibilities for data entry. Maybe it would require max and min properties, but it would be super flexible. Again, not important, just an observation.
-
@Phuket2 That's exactly what Apple's PickerView is π
-
@cvp , but I am i right in saying in Pythonista we dont get that implementation? I am not trying to be smart, just trying to understand it.
-
@Phuket2 yes, you're right. I just tried to make humor π
-
@cvp , lol. Ok understand :)