Forum Archive

Date Picker w/ blank year

osamu

Hi, guys!

Does anybody know if we can implement Date Picker w/ the year left blank?

Blank year is expressed as ----, and I know it's internal expression is the year 1604.

cvp

@osamu hide it

import ui
from  objc_util import ObjCInstance,ObjCClass
d = ui.DatePicker()
d.frame = (0,0,300,100)
d.mode = ui.DATE_PICKER_MODE_DATE
objc = ObjCInstance(d)
back_ui_color = ObjCClass('UIColor').color(red=0.8, green=0.8, blue=0.8, alpha=1.0)
objc.backgroundColor = back_ui_color

h = ui.View()
hc = ObjCInstance(h)
hc.backgroundColor = back_ui_color
w = 100
h.frame = (d.width-w,0,w,d.height)
d.add_subview(h)
d.present('sheet')

osamu

And I failed to embed the image
https://imgur.com/a/XYJrHhD

osamu

@cvp thank you.

what I meant is to enter year 1604 in order to invalidate the year as the following image that I failed to embed:

cvp

@osamu said

And I failed to embed the image

Use

![](url)
cvp

@osamu Ok, I understand, I'll try to hide the year by a normal (ObjectiveC) picker. Back in some hours.

cvp

@osamu I'm still in progress...

cvp

@osamu ok, try this (hoping I had correctly understood, but not sure)
The view title will show the selected date

from   datetime import datetime
import ui
from   objc_util import ObjCInstance,ObjCClass
from   math import pi,cos,sin

#===================== delegate of UIPickerView: begin =====================
def pickerView_numberOfRowsInComponent_(self, cmd, picker_view, component):
    return(len(ObjCInstance(picker_view).data))

def numberOfComponentsInPickerView_(self, cmd, picker_view):
    return 1

def rowSize_forComponent_(self, cmd, picker_view, component):
    return ObjCInstance(picker_view).myRowWidth

def pickerView_rowHeightForComponent_(self, cmd, picker_view, component):
    return ObjCInstance(picker_view).myRowHeight

def pickerView_didSelectRow_inComponent_(self, cmd, picker_view, row, component):
    UIPickerView = ObjCInstance(picker_view)
    UIPickerView.selectedRow = row
    if UIPickerView.myDidSelectRow:
        UIPickerView.myDidSelectRow()
    return

def pickerView_viewForRow_forComponent_reusingView_(self, cmd, picker_view, row, component,view_ptr):
    UIPickerView = ObjCInstance(picker_view)
    if view_ptr == None:
      #view = ObjCClass('UILabel').alloc().init()
      #view.setText_(UIPickerView.data[row])
      uiview = ui.Label()
      uiview.alignment = ui.ALIGN_CENTER
      uiview.text_color = 'red'
      uiview.text = UIPickerView.data[row]
      view = ObjCInstance(uiview)
      view.setClipsToBounds_(True)
      if UIPickerView.horiz:
        a = pi/2
        rot = CGAffineTransform(cos(a),-sin(a),sin(a),cos(a),0,0)
        view.setTransform_(rot, restype=None, argtypes=[CGAffineTransform])
    else:
      view = ObjCInstance(view_ptr)
    return view.ptr

methods = [
    numberOfComponentsInPickerView_, pickerView_numberOfRowsInComponent_, rowSize_forComponent_, pickerView_rowHeightForComponent_, pickerView_didSelectRow_inComponent_, pickerView_viewForRow_forComponent_reusingView_]

protocols = ['UIPickerViewDataSource', 'UIPickerViewDelegate']

UIPickerViewDataSourceAndDelegate = create_objc_class(
    'UIPickerViewDataSourceAndDelegate', methods=methods, protocols=protocols)
#===================== delegate of UIPickerView: end =======================

class MyUIPickerView(ui.View):
    def __init__(self, data, horiz=False,myRowHeight=100, myDidSelectRow=None, **kwargs):
        super().__init__(**kwargs)

        UIPickerView = ObjCClass('UIPickerView')
        self._picker_view = UIPickerView.alloc().initWithFrame_(ObjCInstance(self).bounds()).autorelease()
        ObjCInstance(self).addSubview_(self._picker_view)
        self.delegate_and_datasource = UIPickerViewDataSourceAndDelegate.alloc().init().autorelease()
        self._picker_view.delegate = self.delegate_and_datasource
        self._picker_view.dataSource = self.delegate_and_datasource

        self._picker_view.myRowWidth = self.width
        self._picker_view.myRowHeight = myRowHeight
        self._picker_view.myDidSelectRow = myDidSelectRow
        self._picker_view.data = data
        self._picker_view.horiz = horiz

        if horiz:
          a = -pi/2
          rot = CGAffineTransform(cos(a),-sin(a),sin(a),cos(a),0,0)
          self._picker_view.setTransform_(rot, restype=None, argtypes=[CGAffineTransform])


    def layout(self):
        self._picker_view.frame = ObjCInstance(self).bounds()


v = ui.View()
v.name = 'for @osamu'
v.frame = (0,0,300,150)
d = ui.DatePicker()
d.frame = v.frame
d.mode = ui.DATE_PICKER_MODE_DATE
def d_action(sender):
    d_str = sender.date.strftime('%Y%m%d %H%M%S')
    v.name = d_str
d.action = d_action
v.add_subview(d)
objc = ObjCInstance(d)
back_ui_color = ObjCClass('UIColor').color(red=0.8, green=0.8, blue=0.8, alpha=1.0)
objc.backgroundColor = back_ui_color

years = ['2019','2020','2021','2022','----']
w = 100
def myDidSelectRow():
    #print(pv._picker_view.selectedRow)
    year = years[pv._picker_view.selectedRow]
    if year == '----':
        year = '1604'
    d_str = year + d.date.strftime('%m%d %H%M%S')
    d.date = datetime. strptime(d_str, '%Y%m%d %H%M%S')
    v.name = d_str
pv = MyUIPickerView(years, myRowHeight=32, myDidSelectRow=myDidSelectRow, frame=(d.width-w,0,w,d.height))
pv.background_color = 'lightgray'
#pv.border_width = 1
#pv.border_color = 'blue'
#pv.corner_radius = 5
v.add_subview(pv)
hc = ObjCInstance(pv)
hc.backgroundColor = back_ui_color
v.present('sheet')

italicised text

osamu

@cvp Thank you very much indeed for spending time 🙏
This picker is the one that shows up when you enter birthday and other dates when using contacts app. I’m going to try your code.

cvp

@osamu In this case, the ---- can't be selected but only shows a maximum date.
I think that we can also set this maximum date without all the code I wrote

cvp

@osamu try this little script. You will not see the wanted "----" but after the now-date, day/month/years are grayed and not selectable with automatic return to today picker. I'm sure I'm not clear, thus try it.

import ui
v = ui.View()
v.name = 'for @osamu'
v.frame = (0,0,300,150)
d = ui.DatePicker()
d.frame = v.frame
d.mode = ui.DATE_PICKER_MODE_DATE
v.add_subview(d)
objc = ObjCInstance(d)
nsDate = ObjCClass('NSDate').alloc().init() # initialized with now-date
#print(dir(nsDate))
objc.setMaximumDate_(nsDate)
v.present('sheet')
osamu

@cvp said:

objc.setMaximumDate_(nsDate)

Thank you, I’m interested in the above attribute.

osamu

@cvp I tried the first version but Pythonista claimed create_objc_class() is missing. There may be some more. I guess I need to sneak into your library and steal them.

cvp

@osamu my error

from   objc_util import *
osamu

@cvp I got it. Thank you.

osamu

@cvp This script initializes the year as 2019. If I set;
years = [str(y) for y in range(1605,datetime.now().year+1)] + ['----']
the initial year is set to 1605 and we’re far away from —— and recent years. Can we control this initial value?

JonB

Have you tried reversing the list?

osamu

@JonB That’s a good idea 👍

osamu

@cvp one last question.
Can I set the initial year?
The following does not work.

class MyUIPickerView(ui.View):
    def __init__(self, data, horiz=False,myRowHeight=100, myDidSelectRow=None, **kwargs):
        super().__init__(**kwargs)

        UIPickerView = ObjCClass('UIPickerView')
        self._picker_view = UIPickerView.alloc().initWithFrame_(ObjCInstance(self).bounds()).autorelease()
        ObjCInstance(self).addSubview_(self._picker_view)
       ...
       self._picker_view.selectedRow = XXX

Thanks in advance.

cvp

@osamu selectedRow is not an attribute of UIPickerView but is an user attribute set in the pickerView_didSelectRow_inComponent_ delegate, thus you can't set it.

I think we would need to use kind of

.
.
.
        self._picker_view.horiz = horiz
        xxx = 1
        self._picker_view.selectRow_inComponent_animated_(xxx,0,True)

Tested, ok

osamu

@cvp Yes, it works. Thanks!